Today I am going to write about two-tokens based authentication mechanism that powers a huge segment of today’s internet.

About JWT (JSON Web Token)

  • JWT is a compact, URL-safe token format used for securely transmitting information between parties.
  • Each token is digitally signed (usually with HMAC or RSA), so it can be *validated without querying the database * — making authentication much faster.
  • Access Tokens are bearer tokens sent with every API request to one or more resource servers.
    • Typically stored in browser memory or local storage.
    • Susceptible to XSS attacks, but risk is reduced by keeping their lifespan short (e.g., 5–15 minutes).

Basic Format

JWT is a compact string that is URL=safe(using base64 encoding) consisting of 3 parts separated by dots(.).

1
2
3
4
5
xxxxxxxxxx.yyyyyyyyy.zzzzzzzzzzz
header.payload.signature

// Example
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsImV4cCI6MTcxMjM0NTY3OH0.yQ8s3ZCq1JHc3xJv9jN7k2w9Uq4s2ZPzF9cL2Rz1E7M

You can use https://www.jwt.io/ to check your JWT tokens.

You basically need three types of data to get dot-separated token.

Header

It consists of a JSON object containing info about which algorithm to use to sign the token.

1
2
3
4
{
  "alg": "HS256",
  "typ": "JWT"
}

You can choose from a variety of algorithms like HMAC SHA256(HS256), RSA, Elliptic Curve (ECDSA - ES256) or EdDSA (Ed25519).

Payload

Payload is a JSON that contains information that you want share with the token bearer or client. The properties/keys in the JSON are either from Specification, Publicly Accepted, or, defined by you.

An example payload could be:

1
2
3
4
5
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

Signature

This is the last part in the token and is created by signing the header and payload with the secret.

1
2
3
signature = HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret)

Why a Two-Token Design (Access + Refresh)

Using two tokens instead of one long-lived token is a security best practice that balances user convenience and safety.

  • Single long-lived tokens pose major security risks:

    • If leaked, they allow persistent unauthorized access.
    • Revoking them requires server-side storage or blacklists, defeating JWT’s stateless nature.
  • Access Token

    • Short-lived and stateless — no DB lookup needed for validation.
    • Used to access protected resources quickly and efficiently.
  • Refresh Token

    • Long-lived and stored more securely (e.g., HTTP-only cookie or secure device keystore).
    • Sent only to the authorization server’s token endpoint to get a new access token.
    • Server checks if the refresh token is revoked or expired before issuing a new one.

Where Tokens Are Stored

  • Refresh Tokens
    • Stored in a database table, enabling revocation and tracking.
  • Access Token Secrets / Keys
    • Stored securely in environment variables or key management services (e.g., AWS KMS, Vault).

Benefits & Drawbacks

Aspect Two-Token Design Single-Token Design
Performance Fast access validation (no DB hit) Same, but risks persist
Security Safer — short-lived access, revocable refresh Risky — hard to revoke, long-lived compromise
Complexity Slightly higher (two-token flow) Simpler implementation
Scalability Stateless validation, scalable across services Can require DB checks if revocation added

Why Not Use a Single Token?

Using one long-lived JWT for both access and refresh purposes is dangerous because:

  • Compromise of the token means unlimited access until expiry.
  • You lose the ability to revoke compromised sessions.
  • You must choose between:
    • Short expiry: Poor UX (frequent logins)
    • Long expiry: Severe security risk

Summary

A two-token system (Access + Refresh):

  • Keeps APIs fast (stateless JWT validation).
  • Enables token revocation and rotation for security.
  • Provides a safe, scalable authentication pattern ideal for distributed systems and microservices.