Understanding access tokens, refresh tokens, and token freshness in AuthX
AuthX supports two types of tokens with different purposes and lifetimes. Understanding when to use each type is crucial for building secure authentication systems.
Fresh tokens indicate that the user recently provided credentials. Use fresh tokens to protect sensitive operations:
# Create a fresh token during loginaccess_token = auth.create_access_token( uid="user123", fresh=True # User just logged in)# Refreshed tokens are not freshrefreshed_token = auth.create_access_token( uid="user123", fresh=False # Token from refresh endpoint)
Both token types contain standard JWT claims plus AuthX-specific fields:
from authx.schema import TokenPayload# Decode a tokentoken_payload = auth._decode_token(access_token)# Standard JWT claimstoken_payload.sub # Subject (user ID)token_payload.jti # JWT ID (unique identifier)token_payload.iat # Issued at timestamptoken_payload.exp # Expiration timestamptoken_payload.nbf # Not before timestamptoken_payload.iss # Issuertoken_payload.aud # Audience# AuthX-specific claimstoken_payload.type # "access" or "refresh"token_payload.fresh # True if token is freshtoken_payload.csrf # CSRF token (for cookies)token_payload.scopes # List of scopes
Refer to schema.py:35 for the TokenPayload class definition.
from authx.schema import TokenPayloadpayload: TokenPayload = auth._decode_token(access_token)# Check time until expirationtime_left = payload.time_until_expiryprint(f"Token expires in {time_left.total_seconds()} seconds")# Check time since issuedtoken_age = payload.time_since_issuedprint(f"Token was issued {token_age.total_seconds()} seconds ago")# Get expiration as datetimeexpiry = payload.expiry_datetimeprint(f"Token expires at {expiry}")
See schema.py:112 for expiration-related properties.
Both access and refresh tokens can include scopes for granular permissions:
# Create token with scopesaccess_token = auth.create_access_token( uid="user123", scopes=["users:read", "posts:write", "admin:*"])# Check scopes in payloadpayload = auth._decode_token(access_token)# Check if token has specific scopesif payload.has_scopes("users:read"): print("Can read users")if payload.has_scopes("users:read", "users:write"): print("Can read and write users")if payload.has_scopes("admin:users", "admin:settings", all_required=False): print("Has at least one admin scope")
Refer to schema.py:164 for the has_scopes() method.
Why use both access and refresh tokens?
Using separate token types provides better security:
Minimize exposure: Access tokens are sent frequently but expire quickly
Reduce attack window: Compromised access tokens are only valid briefly
Enable revocation: Refresh tokens can be revoked without affecting active sessions
Support multiple devices: Each device can have its own refresh token
Audit trail: Track refresh token usage for security monitoring