Protect the unauthenticated route in next js - next.js

I'm newly start on next js project , we have added a middlewate in next js to protect the route like below
useEffect(() => {
if (typeof window !== undefined) {
if (router.pathname == "/reset-password") {
// allow before login
}else if (!loginUser.authenticated) {
router.push('./login')
}
else if (loginUser.authenticated && !loginUser.selectedCustomer) {
router.push('./search-customer')
} else if (loginUser.authenticated && loginUser.selectedCustomer) {
if (router.pathname == "/") {
router.push("/stock-items/categories");
}
}
}
}, []);
return <>{props.children}</>;
But the issue is when any one direclty hit the specific route the controller goes to specific page and then nevigate to login screen if user is not login
i'm trying to stop that type of process , if user is not login then then any route should not be nevigate
please help us

useEffect runs on the client-side after the DOM has rendered (the typeof window check is therefore unnecessary).
This means any checks you place in the useEffect will be ran after the user see's the page (even just for a split second).
There are 2 options how you can handle this. Both are mentioned in the authentication guide in NextJS docs. I recommend taking a look.
Option 1
Set loading state default state as true, rendering a loading indicator while you do your authentication checks...
After you finish authenticating, toggle the loading state to false, allowing to render the page.
Option 2 (Recommended)
What you want to do here is take advantage of Next's core features such as getServerSideProps.
The code you put into getServerSideProps runs BEFORE the client receives any HTML payload.
In the getServerSideProps you can do your authentication, check for authentication cookie or Authorization header, depends what authentication method you use, and either redirect the user to /login page.

Related

Firebase Persisting Auth with Stack Navigator

Attempting to let Firebase persist authentication within the app.js of React Native by doing the following:
There is a sign in page that envokes auth() sign in via Firebase, which works fine, and redirects to the home page via navigation.replace("Home"); however, once the app is closed and relaunched on the emulator, it redirects back to sign in.
This is seemingly what the App.js looks like, I assume that the AuthStateChanged would be prevalent as depicted below, however, user is not accessed in App.js as it is established in SignIn.js, when the Firebase credentials are sent, but I assume it would be similar to this layout?
const App = () => {
var initialRoute = null
React.useEffect(() => {
const unsubscribe = auth().onAuthStateChanged(user => {
if(user) {
initialRoute = "Home"
}
else {
initialRoute = "SignIn"
}
})
return unsubscribe
}, []);
return (
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
initialRouteName={initialRoute}
>
The reason it needs to affect the initial route, and not just redirect anyone who reopens to the home page, is because after registration, there are extra steps included that adjust the database, such as location mapping and etc., therefore, the redirection has to occur within the initial route.
Thanks for your assistance.
This is not how you build a navigation flow with react-navigation. But that's no problem since theres a guide here on the official react-navigation side on how to do that: https://reactnavigation.org/docs/auth-flow/
Fixed by setting two different returns within App.js, one for if the user is authenticated with Firebase that sets the initialRoute to "Home", and one for else that sets it to "SignUp", seems to work fine.

404 Page Being Shown While NextJS Page Is Rendering

I build all of my initial routes for a dynamic slug based on what I have available in my CMS at build time. Then as new CMS data is available, I will generate new pages when they are requested by the user.
I'm running into an issue where a user might hit /posts/1, but since posts/1 has no CMS data, I'm rendering the 404 page using the notFound boolean inside of getStaticProps. This is what I expect to happen.
Now, if I publish some data to /posts/1 in my CMS, the next time a user hits /posts/1, the API data is fetched in the getStaticProps method, and the page begins to build. The problem is that the user is immediately redirected to the 404 page even though the notFound block is not hit. The router.isFallback flag is also shown as false when it should be true since the page is building. Now, if this user were to refresh their page, they would see the generated page and no longer the 404 page since it is now built.
It seems like Next might route the user's request to the 404 page in the second scenario since it was previously a 404, but is there some way I can "block" the user's request or show my fallback until the page is rendered so that they don't see this 404 when the page is building? This scenario would not happen if the first user did not hit this slug before there was CMS data available.
Here's a simplified example of how I am using getStaticPaths and getStaticProps:
export const getStaticPaths = async (ctx) => {
const myInitialPaths = await fetch('http://my-cms-endpoint.com/initial-paths/');
return {
paths: [
...myInitialPaths
],
fallback: true
}
}
export const getStaticProps = async ({ params }) => {
const myPageData = await fetch('http://my-cms-endpoint.com/page/#id');
if (myPageData) {
return {
props: {
myPageData
}
}
} else {
return {
notFound: true
}
}
}

Displaying form on first login

I'm trying to work out how I can display a form to a user upon their first login to my app ( to fill in profile information) after which they can proceed to the regular site.
Could anyone point me in the right direction?
Thanks
You can make the trick using app startup script:
https://devsite.googleplex.com/appmaker/settings#app_start
Assuming that you have Profile model/datasource, code in your startup script will look similar to this:
loader.suspendLoad();
var profileDs = app.datasources.Profile;
// It would be more secure to move this filtering to the server side
profileDs.query.filters.UserEmail._equals = app.user.email;
profileDs.load({
success: function() {
if (profileDs.item === null) {
app.showPage(app.pages.CreateProfile);
} else {
app.showPage(app.pages.HomePage);
}
loader.resumeLoad();
},
failure: function() {
loader.resumeLoad();
// your fallback code goes here
}
});
If profile is absolute must, I would also recommend to enforce the check in onAttach event for every page but CreateProfile (to prevent navigation by direct link):
// Profile datasource should be already loaded by startup script
// when onAttach event is fired
if (app.datasources.Profile.item === null) {
throw new Error('Invalid operation!');
}
I suggest checking the user profile upon login. If the profile is not present, display the profile form, otherwise, proceed to the regular site.

Meteor: How do I only allow the user to access on page?

I am using iron router, and I have a special type of account (certain value in Meteor.user().profile) and I am wondering if there is a way using iron router, that instead of having to put a restriction in every single route (except for home. login, etc) that I can simply only allow them one page?
Is there a way to do this?
Check out this page... http://www.manuel-schoebel.com/blog/meteorjs-iron-router-filters-before-and-after-hooks
Basically, you can setup a global onBeforeAction hook that will run before each route, then redirect the user if needed to a default route. You can also use before for specific routes, here's the example from the page...
////////////////
// BeforeHooks
////////////////
// I use an object that contains all before hooks
var IR_BeforeHooks = {
isLoggedIn: function(pause) {
if (!(Meteor.loggingIn() || Meteor.user())) {
Notify.setError(__('Please login.'));
this.render('login');
pause();
}
},
somethingForAnyRoute: function() { ... },
...
// add more before hooks here
}
// (Global) Before hooks for any route
Router.onBeforeAction(IR_BeforeHooks.somethingForAnyRoute);
...
// Before hooks for specific routes
// Must be equal to the route names of the Iron Router route map
Router.before(IR_BeforeHooks.isLoggedIn, {only: ['userAreaA', 'userAreaB']});
Also, triggering your route protection from something in Meteor.user().profile can be a bad idea, since the user can access and change anything in profile from the client console. This should be directly in the Meteor.user() object for security, then it is looked at server side. I'm not an expert in this area, so more research might be required if security is a concern.

First Sign-in after Signup Show Config Page Once Effectively

I'm trying to show a popup or a template page if user has signed in for the first time after sign up basically allowing them configure some stuff on that page before going to dashboard home, It's only needed for convenience and here is what I got (telescope code)
Router.onBeforeAction(hasCompletedChannels);
hasCompletedChannels: function() {
if(!this.ready()) return;
var user = Meteor.user();
if (user && ! userCompletedChannels(user)){
this.render('connectChannels');
} else {
this.next();
}
}
Which I don't really like because this will always run every time, I want it to run just once, And don't even execute the check function. Is it possible to detect first sign in? (After signup)
I think you could just tie it to the specific route. Right now you're tying it to the Router object (every render forces that check as you point out). So if you define your login function to send someone to a specific route after sign-in, you could just verify on that route.
The function Accounts.onLogin gives you a way to do stuff after the login.
Something like
Router.route('profile', {
path: '/profile',
onBeforeAction: function() {
// Check some stoof
// If first time logged in
// render first time template
// else
// this.next() will render the profile page
},
waitOn: function() {
return [
// some subs
];
},
data: function() {
// some data
}
});
I'm assuming that its going to get routed to a page called profile (seems to make sense). You could check for first time logged in by some attribute you use in the user object and the fields you want filled out and force a render of a different template, or a subtemplate. Check out the Iron Router guide for more ideas on ways to configure it.
Best of luck

Resources