This is a sample project that uses Next.js and MongoDB to create users. This project illustrates how to use JWT cookies to authorize user access to protected routes.
- Signup
- Login
- Profile
With these routes, new users can sign up, login, and view a protected route, like the /profile
page.
- Create new users
- Log users in
- Do client side validation for protected routes, like
/profile
To use this project, you will need to create a new MongoDB cluster via a new project. This can be done on MongoDB Atlas.
In the root of the mongo-auth-jwt
directory create a new .env
file with the following information:
PORT = <AnyPortNumber>
DB_ENV = "testing"
FRONTEND_URL = <YourFrontendURL>
MONGO_URL = <YourMongodbURL>
SECRET_JWT_KEY = <AnySuperSecretKey>
Make sure you are in the root directory of this project, mongo-auth-nextjs
. Then, in your terminal:
npm run setup
npm run dev
These commands will install of the dependencies for the frontend and the backend, and start their servers up.
The backend is available at http://localhost:<PORT>
, where PORT
is the one you designated in the .env
file.
Create new user, using the Next js frontend. Visit http://localhost:3000/signup
and create a new user.
"username": "henry",
"email": "henry@gmail.com",
"password": "1234RTD2"
A few things should happen:
- MongoDB Atlas should now show that new user.
- You should get a response that includes the JWT cookie (check Dev Tools > Application > Cookies)
- The client should automatically transition to the
/profile
page and showcase the newusername
.
This file is responsible for connecting mongoose to mongodb.
This contains the User
model. This is used in the resolvers
to create new users and find existing ones.
These are the functions responsible for responding to incoming requests. They create new users, logging existing ones in, and returning JWT to the client.
These are all of the API routes. They each take a resolver
function
These are functions that run for certain routes when requests are made. There's an Auth
middleware function that is responsible for verifying incoming JWT's, when a User tries to access the Profile
route which is protected. The auth route looks for the JWT in the req.header.token
. However, for security purposes this should be transferred over to an httpOnly
cookie.
This file wires all of these pieces up:
- It starts up your express server
- It creates a connection to your database
- It spins up your API
This folder provides some global context to our entire app. It provides core functionality for:
- signing new users up
- logging users in
- logging users out
- fetching users
All of the next js components. Much of the Form
logic has been abstracted away. The primary thing to keep in mind is that when the submit
button is clicked, the client fires off a request to the backend with that users information.
All of the next js pages. For the most part these just display a Form
component.
This directory contains a very important Higher Order Function, withAuth
. This function can wrap any protected page, like profile
, and validate whether the user is signed in via a JWT Cookie. It does this by checking for the cookie via getServerSideProps
. If this user is signed in, let them proceed to the route. Otherwise, navigate them to the login
page.
In practice, it looks like this:
export const getServerSideProps = (context) => {
return withAuth.isAuthorized(context);
};
function ProfilePage(props) {
return (
<ProfilePageStyles>
<Profile />
</ProfilePageStyles>
);
}
export default withAuth(ProfilePage);
Here are a few articles that helped with making this project:
-
Remaining Stateless - JWT + Cookies in Node JS by Ogbonna Basil
-
Client-side Authentication the Right Way (Cookies vs. Local Storage)
-
The Ultimate Guide to handling JWTs on frontend clients (GraphQL)
From here, you can test out the different pieces, and see how it all works. The next step for this project is to try out using Next.js useSWR
package for all client requests. And, eventually transferring the entire backend over to Next.js, serverless functions via the api
folder.