惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Cybersecurity and Infrastructure Security Agency CISA
D
Darknet – Hacking Tools, Hacker News & Cyber Security
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
S
Schneier on Security
L
Lohrmann on Cybersecurity
S
Securelist
P
Palo Alto Networks Blog
SecWiki News
SecWiki News
T
Troy Hunt's Blog
H
Hacker News: Front Page
AWS News Blog
AWS News Blog
Latest news
Latest news
Hacker News - Newest:
Hacker News - Newest: "LLM"
NISL@THU
NISL@THU
The Hacker News
The Hacker News
F
Full Disclosure
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
大猫的无限游戏
大猫的无限游戏
O
OpenAI News
P
Proofpoint News Feed
Know Your Adversary
Know Your Adversary
G
GRAHAM CLULEY
博客园_首页
Attack and Defense Labs
Attack and Defense Labs
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Security Latest
Security Latest
云风的 BLOG
云风的 BLOG
K
Kaspersky official blog
WordPress大学
WordPress大学
www.infosecurity-magazine.com
www.infosecurity-magazine.com
宝玉的分享
宝玉的分享
L
LINUX DO - 热门话题
博客园 - 叶小钗
L
LINUX DO - 最新话题
Martin Fowler
Martin Fowler
N
News | PayPal Newsroom
Project Zero
Project Zero
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
PCI Perspectives
PCI Perspectives
月光博客
月光博客
IT之家
IT之家
Recent Announcements
Recent Announcements
T
The Exploit Database - CXSecurity.com
D
DataBreaches.Net
J
Java Code Geeks
酷 壳 – CoolShell
酷 壳 – CoolShell
Last Week in AI
Last Week in AI
Google Online Security Blog
Google Online Security Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知

Clerk Blog

Going to production with Clerk Deploy Clerk Init: The fastest way to start a new project Introducing Clerk CLI Middleware-based route protection bypass Postmortem: Clerk System Outage (March 10, 2026) Clerk for the AI era Add API Key support to your SaaS in minutes Postmortem: Clerk System Outage (February 19, 2026) Using Clerk in a React Native app Postmortem: DNS Provider Outage (February 10, 2026) How do I implement passkeys in Next.js? Clerk ranked #4 fastest-growing software vendor on Ramp’s December 2025 list How do I handle JWT verification in Next.js? Committing to Agent Identity: Clerk raises $50m Series C from Menlo and Anthropic’s Anthology Fund What is the best way to handle authentication in Next.js App Router? Postmortem: Database Incident (September 14–18, 2025) How do I add authentication to a Next.js app? Introducing Free Trials in Clerk Billing Postmortem: August 28, 2025 - elevated API latency and errors Introducing Mosaic: Bring Your Brand to Every Authentication Flow Multi-tenant authentication: What you need to know (and how Clerk helps) What are the risks and challenges of multi-tenancy? Resilience in Practice: Regional Failover at Clerk Build a Cross-Platform B2B App with Clerk, Expo, and Supabase Highlights from the MiduDev/Clerk Hackathon Add multi-tenancy to an app built with Clerk, Lovable, and Supabase How to build an AI coding rules app with Clerk, Lovable, and Supabase How to Build Multi-Tenant Authentication with Clerk Choosing the right SaaS architecture: Multi-Tenant vs. Single-Tenant Postmortem: June 26, 2025 service outage How to Design a Multi-Tenant SaaS Architecture What is multi-tenancy and why it matters for B2B SaaS How OAuth Works Synchronize user data from Clerk to Supabase Add subscriptions to your SaaS with Clerk Billing Getting started with Clerk Billing Multi-tenant analytics with Tinybird and Clerk How Huntr Migrated 250K Users to Clerk: A Scalable Auth Solution for Startups How to take Clerk to Production How to take your Clerk application to production A practical guide to testing Clerk Next.js applications Implementing multi-tenancy into a Supabase app with Clerk How Clerk integrates with a Next.js application using Supabase How Clerk integrates with Supabase Build a blog with tRPC, Prisma, Next.js and Clerk How to enrich PostHog events with Clerk user data How to build a secure project management platform with Next.js, Clerk, and Neon Validate your SaaS idea while building an audience Postmortem: February 6, 2025 service outage Implement Role-Based Access Control in Next.js 15 Build a Next.js sign-up form with React Hook Form Build a Next.js login page template How to implement Google authentication in Next.js 15 What is middleware in Next.js? How to customize Next.js metadata How to set environment variables in Node.js Building a React Login Page Template How to implement per-user OAuth scopes with Clerk Using Clerk SSO to access Google Calendar and other service data Streamline enterprise customer onboarding with SAML and Clerk Clerk launches EASIE SSO and eliminates SSO fees How to secure Liveblocks Rooms with Clerk in Next.js Securing Node.js Express APIs with Clerk and React Combining the benefits of session tokens and JWTs Build a task manager with Next.js, Supabase, and Clerk Comparing Clerk Webhooks vs Backend API Automate Neon schema changes with Drizzle and GitHub Actions A guide to reading authenticated user data from Clerk Role based access control with Clerk Organizations Mitigating OAuth’s recently discovered Open Response Type vulnerability Per-user B2B monetization with Stripe and Clerk Organizations Build a team-based task manager with Next.js, Neon, and Clerk Building a Hybrid Sign-Up/Subscribe Form with Stripe Elements Welcoming Colin from Zod as our inaugural Open Source Fellow Build a modern authenticated chat application with Next.js, Ably, and Clerk Build a waitlist with Clerk user metadata How to use Clerk with PostHog Identify in Next.js How to secure API Gateway using JWT and Lambda Authorizers with Clerk What are passkeys and how do they work? Comparing Authentication in React.js vs. Next.js How to Add an Onboarding Flow for your Application with Clerk Create Your Own Custom User Menu with Radix - Part 2 Introducing Webhook Workflows with Inngest & Svix Clerk raises $30M Series B from CRV and Stripe Clerk in 2023: A Year in Review Build a Movie Emoji Quiz App with Remix, Fauna, and Clerk Ultimate Guide to Magic Link Authentication Create Your Own Custom User Menu with Radix Introducing has(), protect(), and <Protect> Updated Pricing: 10,000 MAUs Free, and a new “Pro Plan” Next.js Authentication with Clerk: Streamlined SSR Handling Clerk Webhooks: Data Sync with Convex Exploring Clerk Metadata with Stripe Webhooks The Ultimate Guide to Next.js Authentication Empower Your Support Team With User Impersonation Clerk Webhooks: Getting Started A Complete Guide to Session Management in Next.js The Advanced Guide to Passwordless Authentication in Next.js How We Roll – Chapter 10: Roundup How We Roll – Chapter 9: Infrastructure
Adding JWT Authentication to React
Anshuman Bhardwaj · 2023-04-14 · via Clerk Blog

JSON Web Token (JWT) authentication is a method of securely authenticating users and allowing them to access protected resources on a website or application. It's a popular and widely used method of web authentication as it allows for easy and secure user authentication without the need for the server to maintain a session state.

In this process, the server generates a signed JWT and sends it to the client. The client then includes this token in subsequent requests to the server to authenticate themselves. The JWT is usually stored in the browser's localStorage and sent as part of the request's headers.

However, the JWT mechanism can be arduous and error-prone, especially if you're building it from scratch. In this article, you'll learn how to implement JWT in a React application using a standard flow, and then you'll see how much easier it gets when repeating the exercise using Clerk's React authentication.

What Is JWT Authentication?

Before we discuss how a user is authenticated with JWT, let's take a closer look at what it contains:

  1. The header: consists of two parts—the token type, which is JWT, and a signing algorithm, such as HMAC-SHA256 or RSA
  2. The payload: contains the claims—in other words, the statements about an entity (typically, the user) and additional data
  3. The signature: used to verify the JWT's integrity

To authenticate a client using JWT, the server first generates a signed JWT and sends it to the client. The client then includes the JWT in the header (usually the authorization header) of subsequent requests to the server.

The server then decodes the JWT and verifies the signature to ensure that a trusted party sent it. If the signature is valid, the server can then use the information contained in the JWT to authenticate the client and authorize their access to specific resources. The diagram below shows a standard JWT authentication flow.

JWT authentication flow

Advantages and Downsides of Using JWT

Using JWT authentication offers the following advantages:

  1. JWT authentication is stateless: A JWT contains all the information regarding the user's identity and authentication, including the claims. This can be more efficient than storing session information on the server as it reduces the amount of data that needs to be stored and retrieved for each request.

  2. Create anywhere: Another advantage of JWT authentication is that the token can be generated from anywhere, including external services or third-party applications. This allows for flexibility in terms of where and how the token is generated, which can be useful in a microservices architecture where different services may need to authenticate users.

  3. Fine-grained access control: JWT can contain information about the user's role and permissions in the form of claims. This gives the application developers a lot of control over what actions a user is allowed to take.

However, there are also some disadvantages to using JWT authentication:

  1. Hard to invalidate: Invalidating JWTs is only possible if you maintain a list on a shared database, which introduces additional overhead. The database is necessary because if you need to revoke a token or if a user's permissions change, the server won't otherwise be able to determine the status of the token and might give access when it shouldn't. If the JWTs you're using are long-lived—in other words, they have a very long (or no) expiration time specified—it becomes even more important that they're stored in an accessible database.

  2. Size and security concerns: JWTs can sometimes contain unnecessary information that might be useless for the application and, at the same time, make the token larger and more cumbersome to work with. If the JWT is unencrypted, it can also end up revealing too much about the user.

Given these challenges, some would say that using cookies over JWT works better in some instances as a method of authentication; for example, when the application needs to keep track of the user's activity across multiple pages, as cookies can be easily read and written on the server side. Let's compare the two in detail.

Are Cookies Better Than JWT?

To start with, you can create session-based cookies, which automatically expire after the user session is closed, or you can easily set an expiration time for a cookie, which gives more control over session invalidation. You can also use HttpOnly cookies to prevent JavaScript from accessing the cookie information.

However, it's important to note that cookies come with their own flaws. Specifically, as the cookie data is stored on the server and the cookie identifier is stored on the client, they're not entirely stateless like JWTs. This means that the server needs to store and retrieve the cookie data for each request, which would be additional overhead to the authentication process and slow down the application's performance, especially if the number of concurrent users increases.

They're also not ideal for non-browser-based applications, such as mobile and desktop applications. Additionally, cookies can be more vulnerable to certain attacks, such as cross-site scripting (XSS) and cross-site request forgery (CSRF).

Now that we've covered the advantages and some of the potential challenges of JWT authentication, let's see the process in action. In the following section, you'll see how to implement JWT authentication in your React application.

Implementing JWT Authentication in Your React Application

In this tutorial, you'll build a simple full-stack application with authentication in Next.js. Next.js allows you to implement frontend applications using React and a backend API server without setting up another Node.js project. You'll also understand the pitfalls of creating a JWT authentication from scratch and learn to overcome those limitations using the Clerk SDK.

For pure React applications (without Next.js), check out our React authentication solution which handles JWT and other auth methods seamlessly.

The application stores the key to the user's safehouse (a protected resource) and uses JWT authentication to verify their identity. The application shows the user a welcome page, where they can sign in with a username and password. It generates a JWT for the user, which they can use to verify their identity. Once signed in, users will see their safehouse's secret key by exchanging the JWT with the server.

Before you begin, you'll need a code editor like Visual Studio Code. You'll also need Node.js (version 16 or newer) and npm installed. If you want to check out the completed application, you can clone this GitHub repository.

Setting Up the Project

To set up a Next.js project, run the following command:

You'll be prompted on whether you'd like to use TypeScript and ESLint. For simplicity, choose No for TypeScript and then Yes for ESLint.

After you complete the npm installation, open the project in your code editor and change the directory to the project by running cd clerk-jwt-example in your terminal.

To use the browser's default styling, remove all existing styles from styles/globals.css and styles/Home.module.css.

JWT Authentication Using a Standard Flow

In this example, you'll create two pages: /jwt-home and jwt-safehouse. The former will be the login page to collect credentials, and the latter will be the secured page showing secret information.

More specifically, the /jwt-home page accepts the user credentials and requests the /api/auth API endpoint to generate the signed JWT. The application stores the returned JWT in localStorage as the jwt-token key. The /jwt-safehouse acts as the secured page and requests the secret information from the /api/safehouse API endpoint in exchange for the signed JWT. The /jwt-safehouse page then displays the secret information to the signed-in user.

In Next.js, you can create a new application route by creating a new file with the route name under the pages/ folder. Similarly, to create a new API endpoint, you need to create a new file under the pages/api/ folder.

Update the Application Home Page

To access different parts of your application, update the application home page (pages/index.js) to show links to other pages in the application. The code below uses the Link component from next/link, which is the Next.js version of the <a> tag:

Now start the application by running npm run dev in the terminal. Open http://localhost:3000 in a web browser to see the application. You'll see the page, as shown below.

Initial layout

Create a Signed JWT

To create a signed JWT, you first need to install the jsonwebtoken package. jsonwebtoken provides utilities to sign and verify JWTs. Run npm i jsonwebtoken to install the package in your project.

You'll need a JWT signing secret to use with jsonwebtoken. For this, create a new file, .env.local, to store the application's secret credentials. In this file, add a new environment variable, DIY_JWT_SECRET, with a random hash string as a value:

To generate the signed JWT with the user's signInTime and username, create an API route /api/auth by creating the new file pages/api/auth.js. The API route accepts the user credentials, and if the provided password is pikachu, it returns a 200 response with the signed JWT. Otherwise, it returns a 401 response with an error message:

Create a Login with JWT

Now that the /api/auth API endpoint is ready, create the new file pages/jwt-home.jsx and implement a login form component to send user credentials to /api/auth.

The code below implements a React component, Home, that displays a form to collect the user credentials and, on form submission, makes an HTTP POST request to the /api/auth endpoint with the collected credentials.

If the response message is success, it saves the received JWT in localStorage under the jwt-token key. Otherwise, it shows a browser alert with the response message:

JWT flow login page

Exchange the JWT for the Secret Data

The next step is to implement an API endpoint to verify the JWT from the incoming request header. If it's valid, the endpoint should return a 200 response with the secret data; otherwise, it will return a 401 response with an error message.

Create a new file, pages/api/safehouse.js. In this file, copy and paste the following code to verify the incoming JWT from the jwt-token request header:

Display the Safehouse Secret Data

The final step in the flow is to request the secret data from the /api/safehouse API endpoint and display it if the JWT is valid.

To show the secret safehouse data, create the new file pages/jwt-safehouse.jsx with the following code:

The above code implements a SafeHouse component that renders the secret data if the JWT is available in localStorage. Otherwise, it prompts the user to log in with a link to the /jwt-home page.

The component gets the jwt-token from localStorage and makes a fetch request to the /api/safehouse in the useEffect hook that runs on the initial render in the browser.

The Logout button triggers the logout() function that clears the token state variable and removes the localStorage item.

The standard JWT authentication flow is ready.

Note that the solution you implemented above is very naive for a number of reasons. First, to make this system work, you'll need to implement and maintain additional code to track any updates to the JWT and pass the JWT in the request headers.

Next, you can't invalidate the stored JWT from outside the user's browser, which is a critical security issue—if a user's account is suspended or deleted, a JWT issued before that action would still be valid and could be used to authenticate as that user.

Further, if a user's password is changed, a JWT that was issued before the password change would still be valid and could be used to authenticate as the user with the old password.

Authentication Using Clerk

By using the Clerk SDK, you can overcome the limitations discussed above. In the following section, you'll find the steps to implement a more secure and scalable solution for your JWT authentication while retaining the same functionality.

Set Up the Clerk SDK

Below are the steps to setting up the Clerk SDK:

  1. On your Clerk dashboard, click Add application to create a new application.

  2. In the Application name field, type in "JWT Example" and click Finish.

    Create new Clerk application

  3. On the application dashboard, click on API Keys in the left navigation. Then copy the Frontend API key, Backend API key, and JWT verification key.

    Copy Clerk credentials

  4. Save the keys in the file .env.local inside your project:

  5. Install the Clerk SDK by running npm i @clerk/nextjs inside your project.

  6. Add the ClerkProvider in the pages/_app.js file to use the authentication state throughout the application:

Implement Sign In and Sign Up

With the Clerk SDK installed, you can easily set up your sign-in and sign-up pages.

Note: In Next.js, files named pages/sign-in/[[...<anything>]].jsx create a catch-all route that will match /sign-in, /sign-in/a, /sign-in/a/b, and so on.

For the sign-in page, create the new file pages/sign-in/[[...index]].jsx and use the prebuilt <SignIn> component from @clerk/nextjs:

For the sign-up page, create the new file pages/sign-up/[[...index]].jsx and use the prebuilt <SignUp> component from @clerk/nextjs:

Fetch the Secret Data from the API

To use the Clerk SDK with the API endpoints, you must create the file middleware.js at the project root with the following code:

To create the API endpoint /api/clerk-safehouse, create a new file, pages/api/clerk-safehouse.js. If the user is signed in, the API handler returns a 200 response with the safehouseKey. Otherwise, it returns a 401 response with an error message.

This API handler function uses the getAuth utility function from @clerk/nextjs/server to get the user's authentication state on the server:

Display the Secret Data

To display the data from the /api/clerk-safehouse API endpoint, create the new file pages/safehouse.jsx.

In this file, create a SafeHouse component that uses the useUser hook from @clerk/nextjs to get the authentication state. If the user isn't signed in, it returns the prebuilt component <RedirectToSignIn> from @clerk/nextjs that redirects the user to the /sign-in page.

However, if the user is signed in, it'll display the safehouseKey fetched from the API call to the /api/clerk-safehouse endpoint. It also returns the <SignOutButton> that the user can click to sign out of the application:

Update Application Home Page

Finally, update the application home page (pages/index.js) to include the new /safehouse link in the list:

Your React application is ready with end-to-end authentication.

Traditional JWT Authentication vs. Clerk

Now that you've implemented authentication in your React application using the traditional JWT flow and with Clerk, you can see how easy it is to implement a full-fledged authentication using the latter approach.

In the do-it-yourself JWT approach, all responsibilities regarding authentication—such as storing the password, verifying user identity, and crafting a beautiful user experience—fall on your shoulders.

Clerk lifts this burden by offering a full-stack solution for managing user authentication. It not only provides easy integrations on the frontend with prebuilt components but also authentication utilities for the backend API routes. With Clerk, you don't have to worry about password management, user session management, or signing and storing the JWT. It's all managed for you automatically.

Apart from its simplicity, the Clerk SDK also uses short-lived JWTs and HttpOnly cookies to provide an additional layer of security for your application. While short-lived JWTs help to protect against replay attacks and limit the window of opportunity for an attacker to use a compromised token, HttpOnly cookies help to protect against XSS attacks.

Conclusion

In this article, you've successfully set up JWT authentication in a React application. While doing so, you learned more about JWT authentication and how to overcome some of its challenges. In particular, you saw how using a solution like Clerk can tremendously simplify JWT authentication in React and make the process more secure at the same time.

Clerk is a one-stop solution for authentication and customer identity management. It can help you build a flawless user authentication flow that supports login with password, multifactor authentication, and social logins with providers like Google, LinkedIn, Facebook, GitHub, and many more.

Clerk provides beautiful components ready to plug into your application and build the authentication flow in no time. Sign up to try Clerk today.