Authentication with credentials using Next-Auth and MongoDB - Part 2
Tags: webdev, nextjs, react, tutorial
Published: 2021-07-15 18:03:22

In the [last part](https://dev.to/dawnind/authentication-with-credentials-using-next-auth-and-mongodb-part-1-m38), 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](https://next-auth.js.org/getting-started/client#signin).

```js
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.

```js
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](https://next-auth.js.org/getting-started/client#getsession)

### 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.

```jsx
//...
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:

```js
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.

```js
import { useSession } from 'next-auth/client';
```

We will use the session to show and hide the tabs.

```jsx
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.

```js
import { Provider } from 'next-auth/client';
```

> Using the supplied React `<Provider>` allows instances of `useSession()` to share the session object across components, by using `React 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`:

```jsx
<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](https://next-auth.js.org/getting-started/client#signout).

```jsx
<li>
    <button onClick={signOut}>Logout</button>
</li>
```

And that's how we implement authentication with credentials in Next.js.