DEV Community

Cover image for How JWT Authentication Works: Access Tokens, Refresh Tokens, and Secure APIs
Synfinity Dynamics Pvt Ltd
Synfinity Dynamics Pvt Ltd

Posted on

How JWT Authentication Works: Access Tokens, Refresh Tokens, and Secure APIs

Authentication is the backbone of every modern web application. Whether you're building a REST API, a mobile app, or a sprawling microservices architecture, you need a reliable way to answer one question: who is making this request, and what are they allowed to do?

Traditional session-based authentication where the server stores session state in memory or a database works fine for monolithic web apps. But it starts to creak under the weight of distributed systems. Sessions require shared storage across servers, don't scale horizontally, and don't play nicely with mobile apps or third-party API consumers.

This is where JWT (JSON Web Token) comes in. It's become the go-to standard for stateless authentication in APIs, mobile apps, and microservices.

In this article, we'll cover:

  • JWT structure
  • The full authentication flow
  • Access tokens vs refresh tokens
  • How to secure your APIs with JWT
  • Common mistakes developers make (and how to avoid them)

Let's dig in.


2. What Is JWT (JSON Web Token)?

A JWT is a compact, self-contained token format used to securely transmit information between two parties as a JSON object. That information can be verified and trusted because it's digitally signed.

JWTs enable stateless authentication - the server doesn't need to store session data anywhere. All the information needed to verify a user is baked into the token itself.

It's worth separating two terms that get conflated a lot:

  • Authentication - verifying who you are (e.g., logging in with a username and password)
  • Authorization - determining what you're allowed to access (e.g., admin vs regular user)

JWT plays a role in both, but it's fundamentally a carrier of identity and permission claims not a magic security bullet on its own.

Here's the basic flow at a glance:

User Login
    ↓
Server Validates Credentials
    ↓
JWT Generated
    ↓
Client Stores Token
    ↓
Token Sent With API Requests
    ↓
Server Verifies Token
    ↓
Access Granted
Enter fullscreen mode Exit fullscreen mode

3. Understanding JWT Structure

A JWT is made up of three parts, separated by dots:

Header.Payload.Signature
Enter fullscreen mode Exit fullscreen mode

Header

The header describes the token type and the algorithm used to sign it.

{
  "alg": "HS256",
  "typ": "JWT"
}
Enter fullscreen mode Exit fullscreen mode

Payload

The payload contains the claims - statements about the user and additional metadata.

{
  "userId": "123",
  "role": "admin",
  "exp": 1720000000
}
Enter fullscreen mode Exit fullscreen mode

Claims generally fall into three categories:

  • Registered claims - predefined, standard fields like exp (expiration), iss (issuer), and aud (audience)
  • Public claims - custom claims agreed upon between parties, ideally namespaced to avoid collisions
  • Private claims - custom claims meant only for a specific application or system

Signature

The signature is created by combining the encoded header, encoded payload, and a secret (or private key) and running it through the signing algorithm. This is what makes the token tamper-proof: if anyone modifies the payload without the secret, the signature won't match anymore, and the server will reject the token.

Important: JWTs are encoded, not encrypted. Anyone can decode the payload and read it. The signature only guarantees the data hasn't been tampered with it doesn't hide the data.


4. How JWT Authentication Flow Works

Here's what happens end-to-end during login and subsequent requests:

User enters credentials
        ↓
Backend validates username/password
        ↓
Server creates JWT
        ↓
Token returned to client
        ↓
Client stores token
        ↓
Client sends token with API requests
        ↓
Backend verifies token
        ↓
Protected resource returned
Enter fullscreen mode Exit fullscreen mode

Breaking that down into concrete pieces:

  • Login endpoint - accepts credentials, checks them against the database
  • Token generation - on success, the server signs a JWT containing user identity and role claims
  • Middleware verification - every subsequent request runs through middleware that validates the token
  • Protected routes - routes that require a valid token before granting access

5. Access Tokens Explained

An access token is the JWT your client sends with every API request to prove it's authenticated.

Access tokens should be short-lived - typically 15 minutes or less. This limits the damage if a token is ever stolen.

Access Token
Expires: 15 minutes
Enter fullscreen mode Exit fullscreen mode

Access tokens are used for:

  • Authenticating API requests
  • Authorizing access to protected resources
  • Identifying the user making the request

A typical request looks like this:

GET /api/profile
Authorization: Bearer <access_token>
Enter fullscreen mode Exit fullscreen mode

Why keep them short-lived?

  • Reduced security risk if the token leaks
  • Better control over how long a compromised token remains useful
  • A smaller exposure window overall

6. Refresh Tokens Explained

Short-lived access tokens are great for security, but they create a UX problem: if tokens expire every 15 minutes, users would need to log in constantly. That's where refresh tokens come in.

A refresh token is a long-lived credential used solely to obtain a new access token it's never sent to your APIs directly.

Access Token Expired
        ↓
Send Refresh Token
        ↓
Server Validates Refresh Token
        ↓
Generate New Access Token
        ↓
Continue Session
Enter fullscreen mode Exit fullscreen mode

Key considerations when implementing refresh tokens:

  • Longer expiration - days or weeks, rather than minutes
  • Secure storage - never expose these to client-side JavaScript
  • Token rotation - issue a new refresh token every time one is used, invalidating the old one
  • Revocation - maintain a way to invalidate refresh tokens (e.g., on logout or suspected compromise)

7. Access Token vs Refresh Token: Key Differences

Feature Access Token Refresh Token
Purpose API access Generate new tokens
Lifetime Short Long
Sent frequently Yes No
Stored Memory / secure storage Secure storage
Risk Lower Higher
Used by APIs Authentication server

8. Where Should JWT Tokens Be Stored?

Where you store your tokens on the client matters a lot for security.

Local Storage

Pros: Simple to implement.

Cons: Vulnerable to XSS (Cross-Site Scripting) attacks if an attacker injects malicious JavaScript, they can read anything in local storage.

Cookies

Cookies can be made much safer with the right flags:

  • HttpOnly - prevents JavaScript from reading the cookie, mitigating XSS
  • Secure - ensures the cookie is only sent over HTTPS
  • SameSite - protects against CSRF (Cross-Site Request Forgery) by controlling when cookies are sent on cross-site requests

Mobile Applications

Mobile platforms have their own secure storage mechanisms:

  • Android - Keystore
  • iOS - Keychain
  • Flutter - secure storage packages (e.g., flutter_secure_storage)

9. Protecting APIs With JWT Middleware

On the backend, JWT verification typically happens in middleware that runs before your route handlers.

Request
 ↓
JWT Middleware
 ↓
Extract Token
 ↓
Verify Signature
 ↓
Check Expiration
 ↓
Attach User Data
 ↓
Controller Executes
Enter fullscreen mode Exit fullscreen mode

In practice, this looks something like:

app.get("/profile",
  authenticateToken,
  profileController
);
Enter fullscreen mode Exit fullscreen mode

Your middleware is responsible for:

  • Token extraction - pulling the token out of the Authorization header
  • Signature verification - confirming the token hasn't been tampered with
  • Expiration checking - rejecting expired tokens
  • User identification - attaching decoded user data to the request object for downstream handlers

10. JWT Security Best Practices

Use HTTPS Always

Without HTTPS, tokens can be intercepted in transit via man-in-the-middle attacks. This isn't optional.

Keep Access Tokens Short-Lived

5–30 minutes
Enter fullscreen mode Exit fullscreen mode

Validate Token Expiration (and More)

Don't just check that a token exists validate:

  • The exp claim
  • The iss (issuer)
  • The aud (audience)

Use Strong Signing Algorithms

Avoid weak secrets and deprecated algorithms. Use well-vetted algorithms like HS256 (with a strong, random secret) or RS256 (asymmetric signing) depending on your architecture.

Rotate Refresh Tokens

Rotating refresh tokens on every use:

  • Prevents token reuse
  • Helps you detect stolen tokens (if an old, rotated-out token is used again, that's a red flag)

11. Common JWT Authentication Mistakes

Mistake 1: Storing Sensitive Data Inside the JWT

Problem: The JWT payload is encoded, not encrypted anyone can decode and read it.

Never store:

  • Passwords
  • Payment details
  • Other private/sensitive information

Solution: Only include the claims you actually need (user ID, role, expiration).

Mistake 2: Using Long-Lived Access Tokens

Problem: If an access token is stolen, the attacker has a long window of access.

Solution: Keep access tokens short-lived and rely on refresh tokens for longevity.

Mistake 3: Not Validating Tokens Properly

Problem: Simply checking that a token exists isn't enough.

Solution: Always validate:

  • Signature
  • Expiration
  • User status (e.g., is the account still active?)
  • Permissions

Mistake 4: Keeping Refresh Tokens Forever

Problem: A stolen refresh token that never expires can generate unlimited sessions indefinitely.

Solution: Implement rotation, expiration, and revocation for refresh tokens.


12. JWT Authentication in Microservices Architecture

JWT shines in distributed systems because it removes the need for shared session storage between services.

Client
 ↓
API Gateway
 ↓
Auth Service
 ↓
Microservices
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Stateless authentication across services
  • No need for a centralized session store
  • Easier horizontal scaling
  • Enables service-to-service authentication using the same token infrastructure

Each microservice can independently verify the token's signature and check role-based permissions without calling back to a central auth server for every request.


13. JWT vs Session-Based Authentication

Feature JWT Session
Storage Client side Server side
Scalability High Requires session storage
Server memory No session required Required
Best for APIs / mobile / microservices Traditional web apps
Revocation More complex Easier

When to choose which:

  • Choose JWT when you're building APIs, mobile backends, or microservices that need to scale horizontally without shared state.
  • Choose session-based auth when you're building a traditional server-rendered web app where easy revocation and simplicity matter more than statelessness.

14. Implementing Role-Based Authorization With JWT

Authentication and authorization work together but answer different questions:

Authentication: User is logged in
Authorization: User can access admin features
Enter fullscreen mode Exit fullscreen mode

You can embed roles directly in the token payload:

{
  "userId": 123,
  "role": "admin"
}
Enter fullscreen mode Exit fullscreen mode

Then check that role on the backend before allowing access:

if (user.role !== "admin") {
  return forbidden;
}
Enter fullscreen mode Exit fullscreen mode

This pattern is common in:

  • Admin dashboards
  • SaaS applications
  • Enterprise systems with tiered permissions

15. Testing JWT Authentication

Before shipping, run through this checklist:

Authentication

  • ✓ Invalid credentials are rejected
  • ✓ Tokens are generated correctly
  • ✓ Expired tokens are blocked

Security

  • ✓ HTTPS is enabled everywhere
  • ✓ Tokens are stored securely on the client
  • ✓ Refresh tokens are protected from exposure

Authorization

  • ✓ Users cannot access other users' data
  • ✓ Roles are properly validated on every protected route

16. Final Thoughts

JWT authentication offers a scalable, stateless way to secure modern applications especially REST APIs, mobile apps, SaaS platforms, and microservices.

But a secure implementation takes more than just generating a token and calling it done. You need to carefully think through:

  • Token lifecycle (access vs refresh)
  • Storage strategy (cookies vs local storage vs secure device storage)
  • Expiration handling
  • Refresh and rotation mechanisms
  • API-level authorization checks

JWT is a powerful tool but like any tool, its security depends entirely on how well it's implemented.


📚 More Reading

Top comments (0)