Back to blog
Mar 28, 2025
11 min read

OAuth2.0 Auth Tokens: A Comprehensive Guide

Exploring access tokens, refresh tokens, and secure authentication flows in OAuth 2.0 for modern web applications
#Security #Web Development #OAuth 2.0 #Authentication Tokens #API Security
Share this article

Table of Contents

  1. OAuth 2.0 in Real Life: The Netflix Streaming Analogy
  2. Understanding OAuth 2.0 Architecture
    1. 1. Roles in OAuth 2.0
    2. 2. OAuth 2.0 Grant Types
    3. 3. OAuth 2.0 Tokens
  3. Token Anatomy: What’s Inside?
    1. Token Structure in OAuth/OIDC
  4. OAuth 2.0 Flows and Token Usage In-Depth
    1. 1. Authorization Code Flow
    2. 2. Authorization Code Flow with PKCE
    3. 3. Client Credentials Flow
    4. 4. Device Authorization Flow
    5. 5. Resource Owner Password Flow (Legacy)
    6. Flow Selection Guide
  5. Token Lifecycle Management
    1. Token Issuance Process
    2. Access Token vs. Refresh Token Lifecycle
    3. Token Versioning for Policy Updates
  6. 6. Advanced Token Security Mechanisms
    1. Refresh Token Rotation
    2. Token Binding
    3. Layered Token Architecture
  7. OAuth 2.0 in Microservices Architecture
    1. Token Propagation
  8. JWT vs. Opaque Tokens: The Great Debate
    1. Hybrid Approach
  9. Final Takeaways

OAuth 2.0 in Real Life: The Netflix Streaming Analogy

Imagine you’re using Netflix on multiple devices. When you first log in on your smart TV, Netflix doesn’t just give you unlimited access forever - that would be a security risk. Instead:

  1. After entering your username/password, your TV receives a short-lived access token (valid for ~1 hour) that lets you stream content immediately.

  2. Your TV also receives a refresh token that’s securely stored and invisible to you. When your access token expires while binge-watching “Stranger Things,” Netflix uses this refresh token behind the scenes to get a new access token without interrupting your viewing or asking for credentials again.

  3. If someone somehow steals your refresh token from your TV and tries to use it on another device, Netflix’s security systems detect this unusual pattern and invalidate all your tokens, forcing a new login.

This is exactly how modern web applications work with OAuth 2.0 - your browser or mobile app securely manages these tokens to provide seamless access while maintaining security, just like Netflix does across your devices.

Tokens are the backbone of secure API access in modern web and mobile applications. This article explores:

  • How OAuth 2.0 uses access and refresh tokens
  • Token anatomy and cryptographic implementation
  • Detailed OAuth 2.0 flows with sequence diagrams
  • Token lifecycle management
  • Advanced security mechanisms
  • Implementation patterns and anti-patterns

Understanding OAuth 2.0 Architecture

OAuth 2.0 is an authorization framework that enables third-party applications to obtain limited access to a user’s resources without exposing their credentials. It is widely used for delegated authorization in modern web and mobile applications.

1. Roles in OAuth 2.0

OAuth 2.0 defines four primary roles:

  • Resource Owner: The user who owns the protected resources and grants permission for access.
  • Client: The application requesting access to the resource owner’s protected resources.
  • Authorization Server: The server that authenticates the resource owner and issues access tokens.
  • Resource Server: The API or service that hosts the protected resources and validates access tokens.

2. OAuth 2.0 Grant Types

OAuth 2.0 supports multiple grant types, each suited for different use cases:

  • Authorization Code Grant: Used for server-to-server communication and web applications with a backend.
  • Implicit Grant (deprecated): Originally used for single-page applications (SPAs) but now replaced with Authorization Code + PKCE.
  • Client Credentials Grant: Used when the client itself (not a user) needs access to resources.
  • Password Grant (deprecated): Used when the user provides credentials directly to the client (not recommended due to security concerns).
  • Refresh Token Grant: Allows clients to obtain a new access token without requiring user authentication.

3. OAuth 2.0 Tokens

OAuth 2.0 uses different types of tokens:

  • Access Token: A short-lived token used to access protected resources.
  • Refresh Token: A long-lived token used to obtain new access tokens.
  • ID Token (used in OpenID Connect): A token containing user identity claims.

Token Anatomy: What’s Inside?

Token Structure in OAuth/OIDC

Both access tokens and refresh tokens can be implemented as JWTs (JSON Web Tokens), though they serve different purposes and have different characteristics.

Access Token Structure

Access tokens are typically JWTs containing claims about the authenticated user and their permissions:

{
"iss": "https://auth.example.com", // Issuer
"sub": "user123456", // Subject (user ID)
"aud": "https://api.example.com", // Audience (intended recipient)
"iat": 1714768000, // Issued At timestamp
"exp": 1714768800, // Expiry timestamp (13 minutes later)
"jti": "abcd1234-ef56-gh78-ij90", // JWT ID (unique identifier)
"scope": "read:profile write:settings", // Authorized scopes
"role": "admin", // User role (for RBAC)
"tenant_id": "org_987654321", // Multi-tenancy identifier
"azp": "client_app_123", // Authorized party (client ID)
"auth_time": 1714767900 // Time of original authentication
}

Refresh Token Structure

Refresh tokens can also be implemented as JWTs, though with a focus on token management rather than authorization data:

{
"sub": "user123456", // Subject (user ID)
"session_id": "abcd1234-ef56-gh78-ij90", // Unique session identifier
"iat": 1714768000, // Issued At timestamp
"exp": 1715372800, // Expiry timestamp (7 days later)
"jti": "1234567890", // JWT ID (unique identifier)
"client_id": "client_app_123", // Client application ID
"scope": "read:profile write:settings", // Authorized scopes
"device_id": "device_abcdef123456", // Device identifier
"family_id": "session_family_7890", // Token family for rotation
"rotation_counter": 0 // Number of times rotated
}

Regardless of format, refresh tokens are typically validated against server-side records for additional security, with each token mapped to a database entry containing complete session information.


OAuth 2.0 Flows and Token Usage In-Depth

OAuth 2.0 provides multiple grant types (flows) to suit different application types and security requirements. Each flow is designed for specific use cases and security considerations.

1. Authorization Code Flow

The standard flow for server-side web applications that can securely store client secrets.

Resource ServerAuthorization ServerWeb App (Server)UserResource ServerAuthorization ServerWeb App (Server)UserAuthorization RequestAuthentication PromptLogin & ConsentAuthorization CodeCode + Client SecretAccess & Refresh TokensRequest with Access TokenProtected Resource

2. Authorization Code Flow with PKCE

Enhanced security for public clients like mobile apps and SPAs that can’t securely store secrets.

Resource ServerAuthorization ServerPublic ClientUserResource ServerAuthorization ServerPublic ClientUserGenerate code_verifier & challengeAuth Request + code_challengeAuthentication PromptLogin & ConsentAuthorization CodeCode + code_verifierAccess & Refresh TokensRequest with Access TokenProtected Resource

3. Client Credentials Flow

For machine-to-machine (M2M) authentication without user interaction.

Resource ServerAuthorization ServerService/BackendResource ServerAuthorization ServerService/BackendClient ID + SecretAccess TokenRequest with Access TokenProtected Resource

4. Device Authorization Flow

For devices with limited input capabilities (IoT, Smart TVs, CLI apps).

Resource ServerAuthorization ServerUserDeviceResource ServerAuthorization ServerUserDeviceRequest device codeDevice code + user code + verification URLDisplay code & URL to userVisit URL & enter codeRequest consentGrant consentPoll for tokensAccess & Refresh TokensRequest with Access TokenProtected Resource

5. Resource Owner Password Flow (Legacy)

Direct username/password authentication - recommended only for legacy system migration.

Resource ServerAuthorization ServerClientUserResource ServerAuthorization ServerClientUserUsername + PasswordUsername + Password + Client CredentialsAccess & Refresh TokensRequest with Access TokenProtected Resource

Flow Selection Guide

Flow TypeBest ForSecurity LevelUser Interaction
Authorization CodeServer-side web appsHighRequired
Auth Code + PKCEMobile/SPA appsHighRequired
Client CredentialsServer-to-serverHighNone
Device AuthorizationIoT/CLI appsHighRequired (secondary device)
Resource Owner PasswordLegacy systemsMediumDirect credentials

Key Considerations:

  • Always prefer Authorization Code flow with PKCE for modern applications
  • Use Client Credentials only for trusted backend services
  • Avoid Resource Owner Password flow in new implementations
  • Consider Device flow for input-constrained scenarios
  • Implement proper token storage based on client type

Token Lifecycle Management

Token Issuance Process

When an authorization server issues tokens, it follows these steps:

  1. Validate the grant (code, credentials, etc.)
  2. Authenticate the client and/or user
  3. Determine appropriate scopes and permissions
  4. Generate cryptographically secure tokens
  5. Store token metadata for refresh and introspection
  6. Sign the access token (if using JWTs)
  7. Return tokens to the client

Access Token vs. Refresh Token Lifecycle

01010101010101010101010101Refresh Token Validity Access Token Validity Refresh Token Access Token 1 Access Token 2 Access Token 3 ValidityTokensToken Lifecycles

Token Versioning for Policy Updates

Advanced systems implement token versioning to ensure security policy updates are enforced:

# Pseudocode for token versioning
def create_refresh_token(user_id, client_id, scopes):
# Get current security policy version
current_policy_version = get_current_policy_version()
refresh_token = {
"user_id": user_id,
"client_id": client_id,
"scopes": scopes,
"issued_at": current_timestamp(),
"expires_at": current_timestamp() + REFRESH_TOKEN_TTL,
"policy_version": current_policy_version,
"jti": generate_uuid()
}
# Store in database
store_refresh_token(refresh_token)
# Return opaque token that references the stored data
return encode_token(refresh_token["jti"])
def refresh_access_token(refresh_token_jti):
# Retrieve stored token data
stored_token = get_stored_token(refresh_token_jti)
# Check if token policy is current
current_policy_version = get_current_policy_version()
if stored_token["policy_version"] < current_policy_version:
# If major policy change, force re-authentication
if is_major_policy_change(stored_token["policy_version"], current_policy_version):
raise RequireReauthenticationException()
# If minor policy change, update token
else:
update_token_policy_version(refresh_token_jti, current_policy_version)
# Generate new access token
return generate_access_token(stored_token["user_id"], stored_token["scopes"])

6. Advanced Token Security Mechanisms

Refresh Token Rotation

Authorization ServerClient AppAuthorization ServerClient AppIf RT1 is used again (potential theft)POST /token (Refresh: RT1)Validate RT1Mark RT1 as usedNew AT + new RT2POST /token (Refresh: RT1)Detect RT1 reuse!Revoke entire token family401 Unauthorized

Token Binding

Token binding attaches tokens to specific devices or browser instances, preventing token theft across environments. This technique ensures that a token cannot be used outside its originally bound context, mitigating replay attacks.

Layered Token Architecture

Sophisticated systems implement a three-tiered token architecture to enhance security:

  1. Access Token (AT): A short-lived token used for API requests, minimizing exposure in case of leaks.
  2. Refresh Token (RT): A longer-lived token used to obtain new access tokens. Its rotation and binding add extra security.
  3. Device-Bound Token (DBT): A token uniquely bound to a device, ensuring that even if an RT is compromised, it cannot be used from a different device.

OAuth 2.0 in Microservices Architecture

Token Propagation

In microservices environments, tokens need to flow between services securely:

Access Token

Token Validation

Delegated Token

Delegated Token

Delegated Token

Client

API Gateway

Auth Service

Service A

Service B


JWT vs. Opaque Tokens: The Great Debate

Token TypeAdvantagesDisadvantages
JWT- Self-contained (no database lookup)
- Stateless verification
- Contains claims and metadata
- Standard format with library support
- Cannot be revoked without extra mechanisms
- Size limitations (URL safe)
- Claims are visible (though encrypted) to clients
Opaque Tokens- Can be instantly revoked
- No size limitation for metadata
- No sensitive data exposure
- Requires database lookup for validation
- Reduced performance at scale

Hybrid Approach

Many systems use a hybrid approach:

  • JWTs for access tokens (short-lived)
  • Opaque tokens for refresh tokens (revocable)

Access (JWT)

Valid

Invalid

Refresh (Opaque)

Valid

Invalid

Revoked

Request

JWT Validation

Access Granted

Request Denied

Refresh Request

DB Lookup

Issue new JWT

Refresh Denied

  • JWT validation: Fast, and in Memory
  • DB Lookup: Slow, and IO operation

Final Takeaways

  • OAuth 2.0 securely grants API access without password sharing.
  • Access tokens are short-lived credentials for API access.
  • Refresh tokens enable seamless long-term sessions.
  • Use PKCE for all public clients to prevent interception attacks.
  • Implement token rotation to detect and prevent token leakage.
  • Consider token binding to specific devices or sessions.
  • Adopt a layered token architecture for complex systems.
  • Monitor token usage for anomalies and security threats.

By mastering OAuth 2.0’s token mechanisms, you can build robust, scalable, and secure authentication systems for any application architecture.