Home>Developer Toolkit>Store and manage auth tokens in Node.js

Store and manage auth tokens in Node.js

catalyst usecase author
Srilakshmi | Technical writer

Inside the Cookbook

  • Implementing secure token storage
    • Understanding auth tokens and their usage
      • Security considerations for token storage
        • Avoid using local storage
        • Employ session storage for temporary tokens
        • Utilize cookies with HttpOnly and secure attributes
      • Secure Token Management in Node.js
        • Enhancing security with Catalyst
          • Key features of Catalyst
          • Why developers prefer Catalyst authentication:
        • Wrapping up

          Implementing secure token storage

          • Authentication is critical in today's web and mobile applications for assuring user and data security. Auth tokens, such as JSON web tokens (JWT), are frequently used to manage user sessions and API access.

          •  However, storing these tokens safely on the client side is frequently an issue. Improper token storage can lead to vulnerabilities like cross-site scripting (XSS) and cross-site request forgery (CSRF).

          • In this guide, we'll walk through the best practices for securely storing and managing authentication tokens in client-side applications using Node.js, and we'll introduce Catalyst as a potential solution for this purpose.

          Understanding auth tokens and their usage

          Auth tokens are often issued by a server after the user successfully authenticates. These tokens are then used to verify the user’s identity for subsequent API requests. JSON Web Tokens (JWT) are particularly popular, as they are self-contained and hold the user's identity and expiration details within the token itself.

          Tokens can be stored in various places on the client side, such as:

          • Local Storage

          • Session Storage

          • Cookies

          Each storage solution comes with its own set of advantages and security risks. It's important to choose the right storage method and secure the tokens properly.

          Security considerations for token storage

          When managing authentication tokens, it is essential to store them in a way that reduces the risk of exposure to malicious entities. Here are some important points for secure token storage.

          Avoid using local storage

          While local storage is easy to use and retains data through page reloads, it is highly susceptible to cross-site scripting (XSS) attacks. If an attacker manages to inject a harmful script into the application, they can access and steal tokens stored in local storage. Therefore, it is not advisable to use local storage for sensitive tokens like access or refresh tokens.

          Employ session storage for temporary tokens

          Session storage retains data only for the browser tab's open state, which limits the exposure time in case of a breach, as the data is deleted when the tab is closed. However, session storage can also be accessed via JavaScript, making it vulnerable to XSS. To mitigate this risk, it is crucial to implement input sanitization and strong content security policies (CSPs).

          Utilize cookies with HttpOnly and secure attributes

          Storing tokens in cookies can be safer if set up correctly. The HttpOnly attribute prevents JavaScript from accessing the cookie, providing protection against XSS attacks. The Secure attribute ensures that the cookie is only sent over HTTPS, which helps prevent token leakage through unencrypted connections. Additionally, using same-site cookie settings (SameSite=Strict or Lax) can further reduce the risk of cross-site request forgery (CSRF).

          Here’s a quick example of how you might store a JWT in a secure cookie

          Run this in your terminal:

          
          npm init -y
          npm install express jsonwebtoken cookie-parser dotenv
          
            

           

          
          //install dependencies
          const express = require('express');
          const jwt = require('jsonwebtoken');
          const cookieParser = require('cookie-parser');
          require('dotenv').config();
          
          const app = express();
          app.use(express.json());
          app.use(cookieParser());
          
          const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key';
          const REFRESH_SECRET = process.env.REFRESH_SECRET || 'your-refresh-secret';
          
          // Token Expiration
          const ACCESS_TOKEN_EXPIRY = '5m'; // short-lived
          const REFRESH_TOKEN_EXPIRY = '7d'; // long-lived
          
          // Sample
          const user = { id: 1, username: 'claire'};
          
          // In-memory store for refresh tokens (use DB/Redis in production)
          let refreshTokens = [];
          
          // Generate Access Token
          function generateAccessToken(user) {
              return jwt.sign(user, JWT_SECRET, { expiresIn: ACCESS_TOKEN_EXPIRY });
          }
          
          // Generate Refresh Token
          function generateRefreshToken(user) {
              const refreshToken = jwt.sign(user, REFRESH_SECRET, { expiresIn: REFRESH_TOKEN_EXPIRY });
              refreshTokens.push(refreshToken);
              return refreshToken;
          }
          
          // ✅ LOGIN - Issue Access & Refresh Tokens
          app.post('/login', (req, res) => {
              const accessToken = generateAccessToken({ id: user.id, username: user.username });
              const refreshToken = generateRefreshToken({ id: user.id, username: user.username });
          
              res.cookie('token', accessToken, {
                  httpOnly: true,
                  secure: true, // true if using HTTPS
                  sameSite: 'Strict',
                  maxAge: 15 * 60 * 1000 // 15 min
              });
          
              res.cookie('refreshToken', refreshToken, {
                  httpOnly: true,
                  secure: true,
                  sameSite: 'Strict',
                  maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days
              });
          
              res.json({ message: 'Logged in successfully' });
          });
          
          
          // ✅ Protected Route
          app.get('/dashboard', authenticateToken, (req, res) => {
              res.json({ message: `Welcome ${req.user.username}!` });
          });
          
          // ✅ REFRESH TOKEN - Renew Access Token
          app.post('/refresh', (req, res) => {
              const refreshToken = req.cookies.refreshToken;
              if (!refreshToken || !refreshTokens.includes(refreshToken)) return res.sendStatus(401);
          
              jwt.verify(refreshToken, REFRESH_SECRET, (err, decoded) => {
                  if (err) return res.sendStatus(403);
          
                  const newAccessToken = generateAccessToken({ id: decoded.id, username: decoded.username });
          
                  res.cookie('token', newAccessToken, {
                      httpOnly: true,
                      secure: true,
                      sameSite: 'Strict',
                      maxAge: 15 * 60 * 1000 // 15 min
                  });
          
                  res.json({ message: 'Access token refreshed' });
              });
          });
          
          // ✅ LOGOUT - Revoke Tokens
          app.post('/logout', (req, res) => {
              const refreshToken = req.cookies.refreshToken;
              refreshTokens = refreshTokens.filter(token => token !== refreshToken);
          
              res.clearCookie('token');
              res.clearCookie('refreshToken');
              res.json({ message: 'Logged out successfully' });
          });
          
          
          
          
            

           

           

          This Node.js code demonstrates how to securely generate and store a JWT in an HttpOnly, Secure cookie 

          Secure Token Management in Node.js

          You can check out external libraries and tools to implement secure token management on the server-side, such as jsonwebtoken for creating and verifying tokens, and cookie-parser or express-session for handling tokens in cookies or sessions. When building applications with Node.js (particularly with frameworks like Express.js), the best practices for secure token handling:

          • Generate a secure token (e.g., JWT) after a successful login using libraries like jsonwebtoken.

          • Send the token to the client via HTTP headers or secure cookies.

          • Store the token securely on the client-side, preferably in HttpOnly and Secure cookies to protect against XSS attacks.

          • Authenticate subsequent API requests by validating the token on the server using middleware.

          • Implement token expiration and renewal strategies to maintain session security.

          • Revoke tokens by maintaining a blacklist or using short expiration times with refresh tokens.

          These practices help ensure secure, stateless authentication and prevent common web vulnerabilities such as token theft and session hijacking.

          Enhancing security with Catalyst

          Catalyst is a full stack cloud development platform that allows developers to build, test, and deploy applications quickly. Catalyst provides out-of-the-box features such as serverless functions, hosted authentication, database management, and more. Using Catalyst, developers can secure auth tokens and manage sensitive data more efficiently.

          Key features of Catalyst

          • Serverless functions: With Catalyst’s serverless functions, you can manage token validation and storage without worrying about managing backend infrastructure.

          • Scalability and security: Catalyst is built with enterprise-grade security in mind, ensuring your tokens and sensitive data are always safe.

          • Native Catalyst Authentication - A complete, hassle-free authentication system integrated directly into the platform.

          • Hosted Login: A Catalyst-hosted login page where users can register, log in, or reset their passwords. It’s fully customizable to align with your brand.

          • Embedded Login: Easily integrate the login interface into your app using an iframe. Users can authenticate without leaving your site ideal for a seamless user experience.

          • And the best part? After logging in, Catalyst issues a secure JWT, automatically validates it with each request, and stores it safely in HTTPOnly, Secure, SameSite cookies, providing built-in protection against XSS, CSRF, and token theft.

          • Interested in social logins? We’ve got you covered.

          Catalyst also supports third-party authentication options like Google, Facebook, or Apple. With the Catalyst Android and Web SDKs, you can implement OAuth-based login flows in just minutes. Once users authenticate, Catalyst manages everything else session handling, token validation, and security.
           

          Why developers prefer Catalyst authentication

          • No backend authentication code needed

          • Built-in endpoint protection

          • Support for both native and social logins

          • Customizable user interface options

          • Enterprise-level token security

          Wrapping up

          Secure authentication is essential. However, spending days developing and maintaining it? That’s not necessary.

          Catalyst provides exceptional security with no backend hassle.By integrating Catalyst into your authentication flow, you can focus on building great applications while leaving the heavy lifting of secure token management to the platform.

          Check it out now