{"id":8243,"date":"2024-09-21T19:13:55","date_gmt":"2024-09-21T13:43:55","guid":{"rendered":"https:\/\/pheonixsolutions.com\/blog\/?p=8243"},"modified":"2026-11-02T19:59:59","modified_gmt":"2026-11-02T14:29:59","slug":"jwt-authentication-with-access-and-refresh-tokens-in-node-js","status":"publish","type":"post","link":"https:\/\/pheonixsolutions.com\/blog\/jwt-authentication-with-access-and-refresh-tokens-in-node-js\/","title":{"rendered":"JWT Authentication with Access and Refresh Tokens in Node.js"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Post Date: September 21, 2024<br>Last Updated: November 02, 2026<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Authentication and security are crucial for maintaining user privacy and application integrity. One popular method of managing authentication in web applications is JSON Web Token (JWT).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">JWT authentication allows applications to securely exchange information between clients and servers. By implementing access tokens and refresh tokens, developers can manage user sessions while reducing the security risks associated with long-lived authentication tokens.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this tutorial, we will learn how to implement <strong>JWT authentication with access and refresh tokens in Node.js<\/strong> using the <code>jsonwebtoken<\/code> package and Express.js. We will also explore token expiration, middleware authentication, and secure refresh-token storage.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is a JWT?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A JSON Web Token (JWT) is a compact, URL-safe token that carries information between two parties, usually a client and a server.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A JWT consists of three parts:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>1. Header<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The header contains metadata about the token, such as the token type (JWT) and the signing algorithm used (for example, HS256).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>2. Payload<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The payload contains claims or information about the user, such as the user ID, username, and other relevant details.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>3. Signature<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The signature is generated using the encoded header, payload, and a secret key. The server uses it to verify that the token has not been modified.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A JWT is signed, not automatically encrypted. Therefore, sensitive information such as passwords or confidential personal data should never be included in its payload.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Flow of JWT Authentication with Access and Refresh Tokens<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When a user successfully logs in to an application, the server generates two tokens.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Access Token<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A short-lived token used to authenticate API requests.<\/li>\n\n\n\n<li>Typically expires within a few minutes.<\/li>\n\n\n\n<li>Sent with requests to protected endpoints.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Refresh Token<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A long-lived token used to generate a new access token.<\/li>\n\n\n\n<li>Typically remains valid for several days or weeks.<\/li>\n\n\n\n<li>Should be stored securely, preferably in an HTTP-only cookie.<\/li>\n\n\n\n<li>Can be revoked when the user logs out or when suspicious activity is detected.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Why Use Two Tokens?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Access tokens have a short expiration time to reduce the impact of token theft. Refresh tokens allow users to obtain new access tokens without repeatedly entering their login credentials.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, when an access token expires, the client sends a request to the refresh-token endpoint. The server validates the refresh token and generates a new access token if the refresh token is still valid.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before implementing JWT authentication in Node.js, make sure you have:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Basic knowledge of JavaScript and Node.js.<\/li>\n\n\n\n<li>Node.js and npm installed.<\/li>\n\n\n\n<li>Basic understanding of Express.js.<\/li>\n\n\n\n<li>Familiarity with REST API development.<\/li>\n\n\n\n<li>An existing user authentication and login process.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Node.js Implementation<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Install the Required Packages<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">First, install the required packages for JWT authentication and Express.js.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">npm install express jsonwebtoken cookie-parser dotenv<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The packages are used for the following purposes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>express<\/code> \u2013 Creates the Node.js application and handles HTTP requests.<\/li>\n\n\n\n<li><code>jsonwebtoken<\/code> \u2013 Generates and verifies JWT tokens.<\/li>\n\n\n\n<li><code>cookie-parser<\/code> \u2013 Reads cookies from incoming requests.<\/li>\n\n\n\n<li><code>dotenv<\/code> \u2013 Loads environment variables from a <code>.env<\/code> file.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Configure Environment Variables<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create a <code>.env<\/code> file in your project root directory and configure separate secret keys for access tokens and refresh tokens.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">JWT_SECRET=your_access_token_secret\nJWT_REFRESH_SECRET=your_refresh_token_secret\nNODE_ENV=development\nPORT=3000<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Use strong, randomly generated secrets in production. Keep the <code>.env<\/code> file private and never commit it to a public repository.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Generate Access and Refresh Tokens<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When a user successfully logs in, the application generates two JWT tokens.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The access token is configured to expire after one minute for demonstration purposes, while the refresh token expires after 30 days.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const jwt = require('jsonwebtoken');\n\nconst generateTokens = (user) => {\n\n    \/\/ Generate the access token\n    const accessToken = jwt.sign(\n        {\n            userId: user._id,\n            username: user.username\n        },\n        process.env.JWT_SECRET,\n        {\n            expiresIn: \"1m\"\n        }\n    );\n\n    \/\/ Generate the refresh token\n    const refreshToken = jwt.sign(\n        {\n            userId: user._id\n        },\n        process.env.JWT_REFRESH_SECRET,\n        {\n            expiresIn: \"30d\"\n        }\n    );\n\n    return {\n        accessToken,\n        refreshToken\n    };\n};<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Explanation:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>jwt.sign()<\/code> generates a signed JWT.<\/li>\n\n\n\n<li><code>user._id<\/code> identifies the authenticated user.<\/li>\n\n\n\n<li><code>username<\/code> is included in the access token payload.<\/li>\n\n\n\n<li><code>JWT_SECRET<\/code> is used to sign the access token.<\/li>\n\n\n\n<li><code>JWT_REFRESH_SECRET<\/code> is used to sign the refresh token.<\/li>\n\n\n\n<li><code>expiresIn<\/code> specifies how long each token remains valid.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The refresh token contains the user ID, which will be used to identify the user when generating a new access token.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After successful login, return the access token in the response and store the refresh token in a secure HTTP-only cookie.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Store the Refresh Token in an HTTP-Only Cookie<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The refresh token should not be exposed to client-side JavaScript. An HTTP-only cookie helps prevent JavaScript from reading the refresh token during an XSS attack.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The following example shows how to send the tokens after successful user authentication.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const sendTokens = (req, res, user) => {\n\n    const { accessToken, refreshToken } = generateTokens(user);\n\n    res.cookie(\"refreshToken\", refreshToken, {\n        httpOnly: true,\n        secure: process.env.NODE_ENV === \"production\",\n        sameSite: \"strict\",\n        maxAge: 30 * 24 * 60 * 60 * 1000\n    });\n\n    res.json({\n        accessToken\n    });\n};<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Call <code>sendTokens()<\/code> after verifying the user&#8217;s login credentials.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The cookie settings provide the following protections:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>httpOnly: true<\/code> prevents JavaScript from accessing the cookie.<\/li>\n\n\n\n<li><code>secure: true<\/code> sends the cookie only over HTTPS in production.<\/li>\n\n\n\n<li><code>sameSite: \"strict\"<\/code> helps reduce cross-site request risks.<\/li>\n\n\n\n<li><code>maxAge<\/code> sets the cookie lifetime to 30 days.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If your frontend and backend are hosted on different sites, you may need to configure <code>SameSite=None<\/code>, <code>Secure<\/code>, credentialed requests, and appropriate CSRF protection.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 5: Create Middleware to Authenticate Requests<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">To protect API routes, create middleware that verifies the access token sent through the Authorization header.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The client should include the access token in the following format:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>Authorization: Bearer ACCESS_TOKEN<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The middleware checks whether the token exists and verifies its signature and expiration.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const jwt = require('jsonwebtoken');\n\nconst authenticateJWT = (req, res, next) => {\n\n    \/\/ Extract the access token from the Authorization header\n    const authHeader = req.headers.authorization;\n\n    if (!authHeader || !authHeader.startsWith(\"Bearer \")) {\n        return res.status(401).json({\n            message: \"Access token is required\"\n        });\n    }\n\n    const token = authHeader.split(\" \")[1];\n\n    \/\/ Verify the access token\n    jwt.verify(token, process.env.JWT_SECRET, (err, user) => {\n\n        if (err) {\n            return res.status(403).json({\n                message: \"Invalid or expired access token\"\n            });\n        }\n\n        \/\/ Attach the decoded user information to the request\n        req.user = user;\n\n        next();\n    });\n};\n\nmodule.exports = authenticateJWT;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Explanation:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The middleware extracts the token from the Authorization header.<\/li>\n\n\n\n<li>It checks whether the Bearer token is available.<\/li>\n\n\n\n<li><code>jwt.verify()<\/code> validates the token using the access-token secret.<\/li>\n\n\n\n<li>If the token is invalid or expired, the server returns an error.<\/li>\n\n\n\n<li>If the token is valid, the decoded user information is attached to <code>req.user<\/code>.<\/li>\n\n\n\n<li><code>next()<\/code> allows the request to continue to the next middleware or route handler.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Step 6: Create an API Endpoint to Refresh the Access Token<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When the access token expires, the client can request a new access token using the refresh token stored in the HTTP-only cookie.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create a refresh-token handler to verify the refresh token and generate a new access token.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const jwt = require('jsonwebtoken');\n\nconst refreshTokenHandler = (req, res) => {\n\n    \/\/ Get the refresh token from the HTTP-only cookie\n    const refreshToken = req.cookies.refreshToken;\n\n    if (!refreshToken) {\n        return res.status(401).json({\n            message: \"Refresh token is required\"\n        });\n    }\n\n    \/\/ Verify the refresh token\n    jwt.verify(\n        refreshToken,\n        process.env.JWT_REFRESH_SECRET,\n        (err, user) => {\n\n            if (err) {\n                return res.status(403).json({\n                    message: \"Invalid or expired refresh token\"\n                });\n            }\n\n            \/\/ Generate a new access token\n            const newAccessToken = jwt.sign(\n                {\n                    userId: user.userId\n                },\n                process.env.JWT_SECRET,\n                {\n                    expiresIn: \"1m\"\n                }\n            );\n\n            res.json({\n                accessToken: newAccessToken\n            });\n        }\n    );\n};\n\nmodule.exports = refreshTokenHandler;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Explanation:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The refresh token is retrieved from the HTTP-only cookie using <code>req.cookies.refreshToken<\/code>.<\/li>\n\n\n\n<li>The server checks whether the refresh token is available.<\/li>\n\n\n\n<li><code>jwt.verify()<\/code> validates the refresh token using <code>JWT_REFRESH_SECRET<\/code>.<\/li>\n\n\n\n<li>If the refresh token is invalid or expired, the server returns an error.<\/li>\n\n\n\n<li>If the refresh token is valid, a new access token is generated.<\/li>\n\n\n\n<li>The new access token is returned to the client.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The refresh token remains in the cookie until it expires or is cleared. For production applications, implement refresh-token rotation and server-side revocation to prevent the continued use of compromised refresh tokens.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 7: Configure Express Routes<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Now, configure the Express application to use the authentication middleware and refresh-token handler.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The refresh endpoint must be accessible without an access token because its purpose is to obtain a new access token.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const express = require('express');\nconst cookieParser = require('cookie-parser');\nconst dotenv = require('dotenv');\n\nconst authenticateJWT = require('.\/middleware\/authenticateJWT');\nconst refreshTokenHandler = require('.\/controllers\/refreshTokenHandler');\n\ndotenv.config();\n\nconst app = express();\n\napp.use(express.json());\napp.use(cookieParser());\n\n\/\/ Public refresh-token endpoint\napp.post('\/refresh-token', refreshTokenHandler);\n\n\/\/ Protected API endpoint\napp.get('\/profile', authenticateJWT, (req, res) => {\n\n    res.json({\n        message: \"Authentication successful\",\n        user: req.user\n    });\n\n});\n\nconst PORT = process.env.PORT || 3000;\n\napp.listen(PORT, () => {\n    console.log(`Server running on port ${PORT}`);\n});<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Explanation:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>express.json()<\/code> parses incoming JSON request bodies.<\/li>\n\n\n\n<li><code>cookieParser()<\/code> makes cookies available through <code>req.cookies<\/code>.<\/li>\n\n\n\n<li><code>\/refresh-token<\/code> is a public endpoint that validates the refresh token independently.<\/li>\n\n\n\n<li><code>\/profile<\/code> is protected by the <code>authenticateJWT<\/code> middleware.<\/li>\n\n\n\n<li>Only requests with a valid access token can access the protected profile endpoint.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If you are using GraphQL, authentication can also be implemented through the GraphQL context so that protected resolvers receive the authenticated user information. Public login and token-refresh operations should be handled explicitly rather than bypassing authentication through simple request-body string matching.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 8: Implement Refresh Token Revocation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A refresh token can remain valid until its expiration time unless the application implements a revocation mechanism.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For production applications, consider storing refresh-token records or token identifiers in a database. When a user logs out, revoke the corresponding refresh token and clear the cookie.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The following example clears the refresh-token cookie during logout:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">app.post('\/logout', (req, res) => {\n\n    res.clearCookie(\"refreshToken\", {\n        httpOnly: true,\n        secure: process.env.NODE_ENV === \"production\",\n        sameSite: \"strict\"\n    });\n\n    res.json({\n        message: \"Logged out successfully\"\n    });\n\n});<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Clearing the cookie removes it from the browser, but it does not invalidate a copied JWT. For complete revocation, the server must also invalidate the refresh-token record or token identifier stored in the database.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Security Considerations<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When implementing JWT authentication with access and refresh tokens, consider the following security practices:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>1. Refresh Token Storage<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Store refresh tokens in HTTP-only, Secure cookies. Configure appropriate SameSite and CSRF protections based on your application architecture.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>2. Short-Lived Access Tokens<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use short expiration periods for access tokens to reduce the impact of token theft.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>3. Separate Secret Keys<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use separate, strong secret keys for access tokens and refresh tokens. Store them securely as environment variables.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">JWT authentication with access and refresh tokens is an effective approach to managing authentication in Node.js applications.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this tutorial, we explored the structure of JWTs, generating access and refresh tokens, implementing authentication middleware, refreshing expired access tokens, and handling token revocation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">By using short-lived access tokens, securely storing refresh tokens, and implementing proper token validation and revocation mechanisms, developers can build more secure authentication systems for their applications.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">FAQ<\/h2>\n\n\n\n<h4 class=\"wp-block-heading\">1. What is the difference between an access token and a refresh token?<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">An access token is a short-lived token used to authenticate API requests. A refresh token has a longer lifetime and is used to generate new access tokens when the existing access token expires.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">2. Where should refresh tokens be stored in Node.js applications?<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Refresh tokens should preferably be stored in HTTP-only, Secure cookies with appropriate SameSite and CSRF protections. This prevents client-side JavaScript from directly accessing the cookie.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">3. What happens when a refresh token expires?<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">When a refresh token expires, the server rejects the refresh request. The user must authenticate again by logging in to obtain new access and refresh tokens.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Related Links<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/pheonixsolutions.com\/blog\/secure-jwt-token-with-graphql-apis\/\">How to Secure JWT Token with GraphQL APIs<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Official Links<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/jwt.io\/\" target=\"_blank\" rel=\"noopener\">JSON Web Token \u2013 Official Website<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.npmjs.com\/package\/jsonwebtoken\" target=\"_blank\" rel=\"noopener\">jsonwebtoken \u2013 npm Package<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/expressjs.com\/\" target=\"_blank\" rel=\"noopener\">Express.js Documentation<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/nodejs.org\/docs\/latest\/api\/\" target=\"_blank\" rel=\"noopener\">Node.js Documentation<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Consult Our Node.js Development Experts<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Looking for reliable Node.js development, application security, or authentication solutions?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/pheonixsolutions.com\/software-development\/\"><strong>Pheonix Solutions<\/strong> <\/a>provides technology services covering application security, software development, cloud infrastructure, DevOps, and technical support.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Our experts can help you build secure applications, implement authentication mechanisms, and maintain reliable software systems.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/pheonixsolutions.com\/contact\">Contact our experts<\/a> to discuss your requirements.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Post Date: September 21, 2024Last Updated: November 02, 2026 Introduction Authentication and security are crucial for maintaining user privacy and [&hellip;]<\/p>\n","protected":false},"author":507,"featured_media":12787,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_hide_featured_image":false,"_jetpack_featured_image_duplicate_dismissed":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[1022],"tags":[],"class_list":["post-8243","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web-architecture","psol-cat-web-architecture"],"jetpack_publicize_connections":[],"jetpack_shortlink":"https:\/\/wp.me\/phn2x7-28X","jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/pheonixsolutions.com\/blog\/wp-content\/uploads\/2024\/09\/JWT-Authentication-Flow-in-Node.js.png","_links":{"self":[{"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/8243","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/users\/507"}],"replies":[{"embeddable":true,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/comments?post=8243"}],"version-history":[{"count":2,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/8243\/revisions"}],"predecessor-version":[{"id":12810,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/8243\/revisions\/12810"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/media\/12787"}],"wp:attachment":[{"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/media?parent=8243"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/categories?post=8243"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/tags?post=8243"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}