In the last part, I created the signup, login and route along with the and the connection of frontend to the backend. Also, I created the sign-in logic using next-auth.
In this part, I'll mainly focus on the frontend connection using next-auth.
Posting sign in logic
The next-auth client gives us both signIn()
and signOut()
hooks that will make our coding a whole lot easier and our only work is to provide the authentication type we will use to sign-in (in our case i.e credentials
).
Using the
signIn()
method ensures the user ends back on the page they started on after completing a sign-in flow. It will also handle CSRF Tokens for you automatically when signing in with email.
The sign-in hook will always return a Promise
containing an error key:value pair that will tell us if the authentication is successful or not.
You can look into more detail here.
import { signIn } from 'next-auth/client';
//...
const status = await signIn('credentials', {
redirect: false,
email: email,
password: password,
});
console.log(status);
And that's our sign-in logic in place.
But wait, it's not all
Suppose, you're signed in but trying to access the route .../auth
which normally shows us the sign-in or sign-up form.
To protect that route, next-auth also gives us a getSession()
hook to check for the session and determine whether a user is signed in or not.
import { getSession } from 'next-auth/client';
NextAuth.js provides a
getSession()
method which can be called a client or server-side to return a session.It calls /api/auth/session and returns a promise with a session object, or null if no session exists.
More info here
Now, let's add this to our .../auth
route:
We will use useEffect()
and useState()
hooks to tell user that something is loading. As getSession()
returns a promise we need a then chain for getting the session object. If there is a session we will use next/router
to redirect the users to /
page.
//...
const [loading, setLoading] = useState(true);
const router = useRouter();
useEffect(() => {
getSession().then((session) => {
if (session) {
router.replace('/');
} else {
setLoading(false);
}
});
}, []);
if (loading) {
return <p>Loading...</p>;
}
//...
Protect a secured route
On the change password page, we need an authenticated user to do the action, and if any unauthenticated user visits ../profile
they will be redirected to the auth page for sign-in or sign-up.
The getSession()
hook can also be used on the server to check for sessions and do any redirect based on that.
We will use the hook along with getServerSideProps
for checking the session of the user trying to access.
NOTE
When calling getSession() server side, you need to pass {req} or context object.
For securing .../profile
page:
export async function getServerSideProps(context) {
const session = await getSession({ req: context.req });
if (!session) {
return {
redirect: {
destination: '/auth',
permanent: false,
},
};
}
return {
props: { session },
};
}
With all the sign-in and sign-up logic in place, now we will look into the Header for showing and hiding the tabs based on user sign-in or not. And finally the sign-out logic.
Dynamic navbar tabs
The useSession
hook from next-auth is the best way to check for an authenticated user. The hook gives us a session and loading state that will be updated based on fetching the users' session.
import { useSession } from 'next-auth/client';
We will use the session to show and hide the tabs.
function MainNavigation() {
const [session, loading] = useSession();
return (
<header className={classes.header}>
<Link href='/'>
<a>
<div className={classes.logo}>Next Auth</div>
</a>
</Link>
<nav>
<ul>
{!session && !loading && (
<li>
<Link href='/auth'>Login</Link>
</li>
)}
{session && (
<li>
<Link href='/profile'>Profile</Link>
</li>
)}
{session && (
<li>
<button >Logout</button>
</li>
)}
</ul>
</nav>
</header>
);
}
export default MainNavigation;
After noticing a bit we will see there's a flickering in the navbar tabs. That's because it's checking for the session twice. Next-auth has a workaround for this also. It provides a <Provider>
component that shares the session object across multiple components and as a result, useSession
doesn't have to check for session twice.
import { Provider } from 'next-auth/client';
Using the supplied React
<Provider>
allows instances ofuseSession()
to share the session object across components, by usingReact Context
under the hood.This improves performance, reduces network calls, and avoids page flicker when rendering. It is highly recommended and can be easily added to all pages in Next.js apps by using
pages/_app.js
.
We can pass the session object to the <Provider>
component as a prop to avoid checking twice.
If you pass the session page prop to the
<Provider>
you can avoid checking the session twice on pages that support both server and client-side rendering.
Let's add this to our _app.js
:
<Provider session={pageProps.session}>
<Layout>
<Component {...pageProps} />
</Layout>
</Provider>
Now, the header will no longer flicker.
Let's check the sign-out logic.
Sign Out
Next-auth also gives us a signOut()
hook that we can attach with any element onClick()
prop and it will just sign us out. It's as easy as that.
More info here.
<li>
<button onClick={signOut}>Logout</button>
</li>
And that's how we implement authentication with credentials in Next.js.
Top comments (12)
I have an issue after using this logic. I modified it a little, where a user creates a client but when i login with client details, and try to fetch data of logged in client, I'm unable to fetch data of the current client, i figured I'm not able to implement a logic to allow data fetching for current user, do you think you can help out with the logic, i followed your tuts and implemented authentication and its working, just fetching data and displaying for current logged in user
Can you atleast post some snippets or source code so that I can understand a bit better !
hey can you share Source Code of this
Here you go:
Authentication with credentials using Next-Auth and MongoDB
Add MongoDB connect url in a .env file as
MONGO_URI
Hey, just wanted to say thank you for writing this article. This helped me a lot for my assignment!
You're welcome :) glad to help
How to multiple role use custom session and jwt?
Hi, how do you handle signup with others data such as tel, adress, city... and also, how do you handle reset/forgot password??
THAnks.
For signup with other data you've to assign those to the user object before posting it to the database.
You've to implement your own reset or forgot password strategy, for example
Change password
Thanks for the great tutorial!
I Forked your Project to use it with Prisma instead of MangoDB
github.com/j0hannr/next-auth-crede...
And Updated to NextAuth v4
wheatear = whether
thanks man :)