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.

