Tokens Explained
Auris uses three categories of tokens: access tokens, refresh tokens, and ID tokens. Understanding what each token is for, what it contains, and how it should be handled is essential for building secure integrations.
Access Token
The access token is the credential your application uses to call protected APIs. It is short-lived by design — the default expiry is 15 minutes.
What it is
An access token is a signed JWT (JSON Web Token). It is self-contained: the resource server can verify its authenticity by checking the signature without making a network call to Auris, using the public keys from the JWKS endpoint.
What it contains
A decoded Auris access token payload looks like this:
{
"sub": "usr_abc123",
"iss": "https://api.altovar.net",
"aud": "your-client-id",
"iat": 1739880000,
"exp": 1739880900,
"jti": "tok_xyz789",
"type": "user",
"email": "[email protected]",
"roles": ["editor", "viewer"],
"scope": "openid profile email",
"plan": "enterprise"
}| Claim | Description |
|---|---|
sub | Subject — the user ID (unique within the tenant) |
iss | Issuer — the Auris instance URL |
aud | Audience — the client ID of the application |
iat | Issued At — Unix timestamp when the token was issued |
exp | Expiry — Unix timestamp when the token expires |
jti | JWT ID — unique identifier for this token |
type | "user" for regular users, "m2m" for client credentials tokens |
email | User’s email address |
roles | Array of role names assigned to the user |
scope | Space-separated scopes granted |
| Custom claims | Any additional claims configured via Custom Claims in the Console |
How to use it
Send the access token in the Authorization header on every request to a protected API:
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImtleS1pZC0xIn0...When it expires
Access tokens expire after 15 minutes by default. When an API returns 401 Unauthorized with error code TOKEN_EXPIRED, use the refresh token to obtain a new access token. The Auris SDKs handle this automatically when autoRefresh: true is configured.
Refresh Token
The refresh token allows your application to obtain new access tokens without requiring the user to log in again.
What it is
A refresh token is an opaque string — it does not carry any claims and cannot be decoded. It is a random value that Auris stores and validates internally. Its opacity is intentional: it must be sent back to Auris to obtain anything useful.
A refresh token looks like:
rt_7fKp2mXa9qN3vB8yR4tL1wC6jD5sE0uHDefault lifetime
Refresh tokens expire after 7 days of inactivity by default. If the user is active, the token is rotated on each use and the expiry resets. Tenant administrators can configure the expiry in the Auris Console under Settings → Security → Session Policies.
Rotation
Auris uses refresh token rotation: every time you exchange a refresh token for new tokens, the old refresh token is immediately invalidated and a new one is issued. This limits the window of exposure if a refresh token is stolen.
{
"ok": true,
"data": {
"accessToken": "eyJhbGciOiJSUzI1NiJ9...",
"refreshToken": "rt_NEW_rotated_token...",
"expiresIn": 900
}
}Security considerations
- Store refresh tokens in
httpOnlycookies (not accessible to JavaScript) when possible - If storing in memory or
localStorage, accept the XSS risk tradeoff - Never include refresh tokens in URLs or log files
- The access token’s short lifetime limits damage if it is intercepted — the refresh token is the higher-value credential
ID Token
The ID token is an OIDC concept. It is issued alongside the access token when the openid scope is requested.
What it is
An ID token is a signed JWT containing the user’s identity claims. It is meant to be consumed by the client application — not sent to APIs. APIs should verify the access token, not the ID token.
What it contains
{
"sub": "usr_abc123",
"iss": "https://api.altovar.net",
"aud": "your-client-id",
"iat": 1739880000,
"exp": 1739883600,
"email": "[email protected]",
"email_verified": true,
"name": "Alice Smith",
"given_name": "Alice",
"family_name": "Smith",
"picture": "https://cdn.example.com/avatars/alice.jpg"
}The ID token has a longer lifetime than the access token (typically 1 hour) because it is only used for display purposes on the client, not for API calls.
When to use it
- Display the user’s name and avatar in your UI without an extra API call
- Verify the user’s identity in a server-side rendered application
- Pass user context to third-party widgets that accept OIDC tokens
Do not use the ID token to authorize API calls.
JWT Structure
All JWTs (access tokens and ID tokens) share the same three-part structure, separated by periods:
header.payload.signatureEach part is Base64URL-encoded (URL-safe Base64 without padding). The three parts are:
Header
{
"alg": "RS256",
"kid": "key-id-1",
"typ": "JWT"
}| Field | Description |
|---|---|
alg | Signing algorithm (RS256 or HS256) |
kid | Key ID — identifies which public key to use for verification (from JWKS) |
typ | Token type — always JWT |
Payload
The claims object described above.
Signature
For RS256: RSASHA256(base64url(header) + "." + base64url(payload), privateKey)
The signature ensures the token has not been tampered with. Anyone can decode the header and payload (they are just Base64), but only Auris (holding the private key) can produce a valid signature.
Decoding a JWT does not validate it. Always verify the signature against the public key before trusting the claims. Use a JWT library or the Auris SDK — never manually decode tokens in production code without verification.
Signing Algorithms
Auris supports two signing algorithms, configured via the JWT_ALGORITHM environment variable:
RS256 (Recommended)
RSA + SHA-256. Asymmetric — Auris signs with a private key, resource servers verify with the public key. The public key is exposed via the JWKS endpoint.
Advantages:
- Resource servers can verify tokens locally without contacting Auris
- The private key never leaves the Auris server
- Standard support in all major JWT libraries
- Compatible with all standard OIDC libraries
HS256
HMAC + SHA-256. Symmetric — the same secret is used for both signing and verification. Both Auris and the resource server must know the shared secret.
Auris supports HS256 for compatibility with certain legacy integrations. RS256 is strongly preferred for new deployments.
JWKS Verification
Resource servers verify access tokens by fetching the signing keys from the JWKS endpoint and using them to validate the JWT signature locally.
JWKS Endpoint
GET /.well-known/jwks.jsonResponse
{
"keys": [
{
"kty": "RSA",
"use": "sig",
"kid": "key-id-1",
"alg": "RS256",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM...",
"e": "AQAB"
}
]
}Verification Steps
- Decode the JWT header (without verifying the signature) to extract the
kid(key ID) - Fetch the JWKS endpoint (or use a cached version — recommended TTL: 1 hour)
- Find the key in the JWKS response whose
kidmatches the header’skid - Use that public key to verify the JWT signature
- Verify that
expis in the future,issmatches your Auris domain,audmatches your client ID
Most JWT libraries handle steps 1-5 automatically when given a JWKS URL. Example using the jose library:
import { createRemoteJWKSet, jwtVerify } from 'jose'
const JWKS = createRemoteJWKSet(
new URL('https://api.altovar.net/.well-known/jwks.json')
)
async function verifyToken(token: string) {
const { payload } = await jwtVerify(token, JWKS, {
issuer: 'https://api.altovar.net',
audience: 'your-client-id',
})
return payload
}Key Rotation
Auris periodically rotates signing keys to limit the impact of key compromise. The rotation process:
- A new RSA key pair is generated and added to the JWKS endpoint with a new
kid - New tokens are signed with the new key
- Old tokens (signed with the old key) continue to be valid because the old public key remains in the JWKS response
- The old key is removed from JWKS only after all tokens signed with it have expired
This means the JWKS endpoint can return multiple keys simultaneously. Clients must look up the key by kid, not always use the first key in the array.
Token Lifecycle
Understanding the full token lifecycle helps you handle edge cases correctly:
Login
→ Receive access token (15 min) + refresh token (7 days) + ID token (1 hr)
↓
Use access token on API calls
↓
Access token expires (401 TOKEN_EXPIRED)
↓
Exchange refresh token → new access token + new refresh token
↓
Continue using new access token
↓
User logs out / refresh token expires / refresh token revoked
↓
User must authenticate againStorage Best Practices
Browser Applications (SPA)
| Storage | Security | Notes |
|---|---|---|
httpOnly cookie | Highest | Not accessible to JavaScript — protects against XSS. Requires same-site or CORS setup. |
sessionStorage | Medium | Cleared when tab closes. Vulnerable to XSS. |
localStorage | Medium | Persists across sessions. Vulnerable to XSS. |
| URL fragment / query string | Lowest | Never do this — tokens appear in browser history and server logs |
The Auris SDK stores tokens in localStorage by default for convenience. For higher-security applications, configure the SDK to use the CookieBridgeStorage adapter which writes to httpOnly cookies via a same-origin endpoint.
Server-Side Applications
Store the refresh token in the user’s server-side session (encrypted at rest). Issue short-lived access tokens on-demand and cache them in memory for their remaining lifetime. Never store access tokens in the database.
Mobile Applications
Use the platform’s secure credential storage:
- iOS: Keychain Services
- Android: Android Keystore
- React Native:
react-native-keychainor Expo SecureStore
Never store tokens in AsyncStorage on mobile — it is not encrypted.
The Auris React SDK (@auris/react) manages token storage automatically. Unless you are implementing a custom integration, you do not need to handle token storage yourself.
Related Concepts
- OAuth 2.0 & OIDC — The protocol layer that issues tokens
- PKCE Flow — How tokens are obtained via Authorization Code + PKCE
- Sessions & Token Rotation — Session lifecycle and refresh token rotation
- DPoP (Proof of Possession) — Binding tokens to cryptographic keys
- Custom JWT Claims — Adding custom claims to access tokens
- Authentication API — Token issuance and refresh endpoints
- JavaScript SDK — Token management in the browser SDK