

























Authentication is core to building any multi-user product, and it's important to get it right from the start.
There are a number of methods you can use when adding authentication into a product, and Next.js has its own paradigms to consider. Understanding the Next.js authentication strategies available is key to knowing which is best for your application, and properly implementing it is the next challenge.
In this article you'll learn about the most common authentication strategies, as well as how to add JWT authentication to a Next.js application.
There are many strategies to select from when planning your approach to authentication. The most common approaches are session token authentication, JWT-based authentication, and OAuth. Let's touch on how each of these compare.
Session token authentication is the oldest on this list but is still widely used today. When a user signs into an application using session token authentication, the backend service will verify the user's credentials against the database and, assuming they are valid, create an entity called a "session". Each session has some commonly tracked attributes stored such as the user it's associated with, when it was created, when it expires, and its status (valid, expired, etc). The session identifier is sent back to the user's device to be used with subsequent network requests.
The most common method of storing the session ID client-side is in a browser cookie so the ID is sent with future network requests automatically. When received by the server, the session is cross-referenced with the user for which it was created so that the server knows who is making the request and can apply security appropriately.
JSON Web Tokens (JWTs) are specially formatted strings that contain embedded information about a particular user or session and are cryptographically signed by the server. When a user signs in, the server will validate the user's credentials just like with session token authentication but instead of creating a session record (commonly in a database table), the details are encoded into a JWT and signed before being sent back to the client. The JWT is also sent with each request but since it contains the user and/or session details, the server does not have to look up those in the database. The server can simply verify the JWT signature is valid and can trust the encoded details if it is.
This has some benefits and drawbacks. One of the primary benefits is the speed by which requests are validated as no datastore lookups are required. Since verification is mostly performed on the receiving server, this also makes JWT authentication more scalable than session token authentication. As long as a server has a cached version of the signing secret (or public key in asymmetric signing configurations), that server can verify the JWTs authenticity.
The primary drawback is the lack of control if a JWT is leaked to an unauthorized party. Since all of the session information is embedded with the token and the verification process does not require any additional checks with a central datastore, there is no standard way to invalidate tokens once they've been signed and sent out.
OAuth is a standard that allows a user to authenticate with one system and access multiple services using a single account. If you've ever signed into a web application with a Google or Apple account, you've used OAuth. In a typical configuration, the service provider (SP) will redirect users attempting to sign in to an identity provider (IdP) to supply their credentials and create a session. Once authenticated, the user's device will receive a code that can be provided to the SP, which will communicate with the IdP to verify the code, create the JWT, and send it back to the user.
This flow (known as the "Authorization Code Grant") describes how the SP and IdP work together to create the session and is only one of many flows that are part of the OAuth spec.
Now that you have a solid understanding of some common authentication strategies, let's learn how to manually implement Next.js authentication using JWT tokens. To do this, you'll step through the following:
To follow along, you'll need the following:
You'll use the supplied starter repository that is a Next.js application preconfigured with SQLite, a few shadcn/ui components, and a dashboard page with some dummy data. Through this guide, you'll create the sign-up page, sign-in page, sign-out button, and you'll configure the middleware to enforce authentication on the /dashboard route.
Upon signing in, the middleware will parse the JWT (stored as a cookie) to determine the user's authentication status. Server actions will be used throughout the various authentication functions.
The following dependencies are also pre-installed:
bcrypt to salt and hash user passwords before storing them in the database.jose to create and validate JWTsBefore moving on, clone the start branch of this repository: clerk/nextjs-jwt-auth-demo. Once cloned, open the project in your code editor of choice and run pnpm install to install the dependencies.
You'll start by creating a helper file that lets the application interact with the SQLite database. The helper will create the connection, create the users table if it does not yet exist, and return a connection object to the caller. The table needed to support user authentication contains only three columns:
id is the unique identifier for the userusername is their usernamepassword_hash is the salted and hashed representation of their passwordCreate the src/lib/db.ts and populate it with the following:
Next, you'll create the JWT helper file that contains the configuration for jose as well as the createToken function to generate a new JWT for the user and parseToken which verifies the token's validity and returns the claims (the data encoded within JWTs) to the caller if it is.
Create the src/lib/jwt.ts file and add the following:
Notice in the above code that the JWT_PRIVATE_KEY and JWT_PUBLIC_KEY are being referenced from the environment variables. To set this up, run the following command in your terminal to generate a key pair and set them in the .env.local file:
Inspecting the .env.local file will look similar to the following (albeit with a larger value for each variable):
Before users can sign-in and use the application, they'll need a way to sign-up first. Create the src/app/actions.ts file to store the server actions required to sign-up. This configuration will check if a record with that username exists (responding with an error if found), creates the JWT and stores it as a cookie, and redirects the user to the /dashboard route.
Now create the src/app/sign-up/page.tsx file to store the sign-up form used to create an account:
You can now start the application with npm run dev, access it using the provided URL, and navigate to the /sign-up route to create a user. After creating a user, you'll be redirected to the /dashboard route.
Since the JWT is stored in a cookie with the httpOnly flag, client-side JavaScript will not be able to access it, so you'll need to configure a server action to clear the cookie. Update the actions.ts file and append the signOut function as shown below:
Next, create a Sign Out button component at src/components/SignOutButton.tsx and paste in the following:
Then you'll need to update the Navigation component to check if the user is logged in and render the button if they are. Since it is a server-rendered component, you can use the next/headers package to access the request cookies and the parseToken function to verify the user is signed in.
Update the src/components/Navigation.tsx file as follows:
Now access the application in your browser once again and click the Sign out button in the navigation. You'll be redirected if you are on the /dashboard page and the navigation bar will update to show the Sign in and Sign up links.
Now that sign-up and sign-out are working, you'll need a way for existing users to sign-in. Update the actions.ts file once again and append the following actions:
Then create the src/app/sign-in/page.tsx file to display the sign-in form:
In the application, navigate to the /sign-in route and use the credentials you created earlier to sign-in and access the /dashboard route once again.
As of now, even unauthenticated users can access /dashboard if they enter the path in their browser. Next.js authentication middleware can be configured to intercept inbound requests and check the cookies to ensure a user is signed-in before allowing them to access protected routes. Furthermore, the middleware can also be configured to redirect unauthenticated users to /sign-in if they attempt to access /dashboard.
Create the src/middleware.ts file and populate it like so to achieve this protection:
Since the /dashboard route is protected by our Next.js authentication system, any users that can access it will have already signed in, meaning the information in the JWT can be trusted. The next/headers package can be used in page content just like in the Navigation.tsx component to parse details about the authenticated user and render the details on the page.
To do this, update src/app/dashboard/page.tsx as follows to display the user's username in the page header:
Accessing the /dashboard page will now show the username in the welcome message!
You now have a functional system that allows users to sign up and sign in to this demo app, however there are a number of missing, critical user management features:
These are just to name a few of the gaps. Production-ready authentication in Next.js goes well beyond basic JWT implementation, and this is where Clerk's Next.js authentication solution comes in.
Clerk is a complete user management platform that allows developers to add enterprise-grade Next.js authentication into their applications as quickly as possible. With Next.js applications, this can be done in just a few lines of code.
Once implemented, you'll automatically gain all of the features listed above along with many more such as:
If you're ready to implement a robust Next.js authentication solution for your Next.js application, check out our Next.js quickstart guide to learn how to get authentication added to your application in as little as 2 minutes. You'll have a complete, secure, and scalable authentication system without the complexity of building and maintaining it yourself.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。