Step-by-Step Guide for Access and Refresh Tokens

Step-by-Step Guide for Access and Refresh Tokens

Whenever we set up authentication and authorization using JWT (JSON Web Tokens), it's important to ensure the use of refresh tokens to enhance security and provide continuous access without requiring the user to log in frequently.

Authentication vs Authorization

Authentication is about confirming ‘who you are’. It's the process of verifying your identity, like when you log in to a website with a username and password. The system checks if you are who you say you are.

Authorization is about checking ‘what you are allowed to do’. After you're authenticated, the system checks if you have permission to access certain resources or perform specific actions, like viewing a page or editing a file.

JWT

JWT (JSON Web Token) is like a digital ID card. When you log in to a website or app, the server gives you this "ID card" (the JWT), which proves who you are.

  • It's a small piece of information, made up of three parts: header, payload, and signature.

  • You send this token every time you make a request (like visiting a new page or getting data) to prove you're logged in.

  • The server doesn't need to look you up in a database every time—it just checks the token.

Think of JWT as a fast and secure way for the server to remember who you are and what you're allowed to do.

Parts of JWT

A JWT consists of three parts separated by periods ‘.’, which are base64url-encoded strings:

  1. Header: The header typically consists of two parts;

    a. the token type (JWT)

    b. the signing algorithm being used, such as HMAC SHA256 or RSA.

    Example

     {
      "alg": "HS256",
      "typ": "JWT"
     }
    
  2. Payload: The payload contains the claims, which are statements about the user or other data. Claims can be of three types: registered, public, and private claims.

    Example:

     {
       "sub": "user1",
       "name": "Sankarlal",
       "admin": true
     }
    

    Signature: To create the signature part, you need to take the encoded header, encoded payload, a secret, and the algorithm specified in the header, then sign that with the secret. The signature is used to verify that the sender of the JWT is who it says it is and to ensure that the message wasn’t changed along the way.

    Example (using HMAC SHA256):

  3.   HMACSHA256(
        base64UrlEncode(header) + "." + base64UrlEncode(payload),
        secret
      )
    

Working of JWT

When a user logs in or attempts to access a protected resource, the server generates a JWT after successful authentication(login process).

The client then stores this token, usually in local storage or a cookie.

For every subsequent request that requires authentication, the client sends the JWT in the request headers.

The server checks the token to make sure it’s valid and that the user has the right permissions before allowing access.

ACCESS TOKENS

Access tokens are temporary keys that allow users to access specific resources after logging in. They contain user information and are sent with requests to verify permissions, usually expiring after a short time for added security.

REFRESH TOKENS

A refresh token is a special type of key that helps you get new access tokens. This way, you can use short-lived access tokens that expire quickly without needing to log in again each time one runs out.

Access tokens contain user information and are valid for a short time. Refresh tokens, on the other hand, are kept safe as HTTP-only cookies(a type of cookie that can only be accessed by the server and not by client-side scripts, such as JavaScript). They allow you to stay logged in longer without risking your sensitive information being accessed by client-side JavaScript.

Integrating Access and Refresh Tokens

Step 1: Setup Environment

  • Install Dependencies: Make sure you have the necessary packages installed: dotenv, express, cookie-parser, and jsonwebtoken.

  • Environment Variables: Set up your .env file with two secrets:

      ACCESS_TOKEN_SECRET=your_access_token_secret
      REFRESH_TOKEN_SECRET=your_refresh_token_secret
    

Step 2: Initialize Express App

  • Create an Express Application: Use Express to handle HTTP requests.

  • Middleware Configuration: Set up middleware to parse JSON and URL-encoded data, and to handle cookies.

  •     const app = express();
        app.use(express.json());
        app.use(express.urlencoded({ extended: false }));
        app.use(cookieparser());
    

Step 3: Define User Credentials

  • Simulated User Data: Create an object with sample user credentials for authentication.

  •     const userCredentials = {
            username: 'sankar',
            password: 'sankarlal2024',
            email: 'sankarlal@gmail.com'
        }
    

Step 4: Implement Login Route

  • Handle Login Requests: Create a POST endpoint /login to authenticate users.

  • Check Credentials: Verify the provided username and password against the stored credentials.

  •     app.post('/login', (req, res) => {
           // Destructuring username & password from body
            const { username, password } = req.body;
    
           // Checking if credentials match
            if (username === userCredentials.username &&
                password === userCredentials.password) {
    
          //creating a access token
               const accessToken = jwt.sign({
                username: userCredentials.username,
                email: userCredentials.email
                 }, process.env.ACCESS_TOKEN_SECRET, { expiresIn: '10m' });
    
         // Creating refresh token not that expiry of refreh token
    
                const refreshToken = jwt.sign({
                    username: userCredentials.username,
                }, process.env.REFRESH_TOKEN_SECRET, { expiresIn: '1d' });
    
                // Assigning refresh token in http-only cookie 
                res.cookie('jwt', refreshToken, {
                    httpOnly: true,
                    sameSite: 'None', 
                    secure: true,
                    maxAge: 24 * 60 * 60 * 1000
                });
                return res.json({ accessToken });
            }
            else {
                // Return unauthorized error if credentials don't match
                return res.status(406).json({
                    message: 'Invalid credentials'
                });
            }
        })
    

Step 5: Implement Token Refresh Route

  • Handle Refresh Requests: Create a POST endpoint /refresh to obtain a new access token using the refresh token.

  • Verify Refresh Token: Check if the refresh token exists and is valid.

  •     app.post('/refresh', (req, res) => {
            if (req.cookies?.jwt) {
    
         // Destructuring refreshToken from cookie
                const refreshToken = req.cookies.jwt;
    
          // Verifying refresh token
                jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET,
                    (err, decoded) => {
                        if (err) {
                            // Wrong Refesh Token
                    return res.status(406).json({ message: 'Unauthorized' });
                        }
                        else {
                            // Correct token we send a new access token
                            const accessToken = jwt.sign({
                                username: userCredentials.username,
                                email: userCredentials.email
                            }, process.env.ACCESS_TOKEN_SECRET, {
                                expiresIn: '15m'
                            });
                            return res.json({ accessToken });
                        }
                    })
            } else {
                return res.status(406).json({ message: 'Unauthorized' });
            }
        })
    

Step 6: Start the Server

  • Run the Application: Listen on a specified port to start the server.

  •     app.listen(6700, () => {
            console.log(`Server active on http://localhost:${6700}!`);
        });
    

So this code demonstrates how to use access tokens for immediate access and refresh tokens for prolonged authentication. The access token is short-lived and needs to be refreshed periodically using the refresh token stored securely in an HTTP-only cookie, ensuring better security and user experience.