Skip to Content
ConceptsTokens Explained

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" }
ClaimDescription
subSubject — the user ID (unique within the tenant)
issIssuer — the Auris instance URL
audAudience — the client ID of the application
iatIssued At — Unix timestamp when the token was issued
expExpiry — Unix timestamp when the token expires
jtiJWT ID — unique identifier for this token
type"user" for regular users, "m2m" for client credentials tokens
emailUser’s email address
rolesArray of role names assigned to the user
scopeSpace-separated scopes granted
Custom claimsAny 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_7fKp2mXa9qN3vB8yR4tL1wC6jD5sE0uH

Default 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 httpOnly cookies (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.signature

Each part is Base64URL-encoded (URL-safe Base64 without padding). The three parts are:

{ "alg": "RS256", "kid": "key-id-1", "typ": "JWT" }
FieldDescription
algSigning algorithm (RS256 or HS256)
kidKey ID — identifies which public key to use for verification (from JWKS)
typToken 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:

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.json

Response

{ "keys": [ { "kty": "RSA", "use": "sig", "kid": "key-id-1", "alg": "RS256", "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM...", "e": "AQAB" } ] }

Verification Steps

  1. Decode the JWT header (without verifying the signature) to extract the kid (key ID)
  2. Fetch the JWKS endpoint (or use a cached version — recommended TTL: 1 hour)
  3. Find the key in the JWKS response whose kid matches the header’s kid
  4. Use that public key to verify the JWT signature
  5. Verify that exp is in the future, iss matches your Auris domain, aud matches 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:

  1. A new RSA key pair is generated and added to the JWKS endpoint with a new kid
  2. New tokens are signed with the new key
  3. Old tokens (signed with the old key) continue to be valid because the old public key remains in the JWKS response
  4. 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 again

Storage Best Practices

Browser Applications (SPA)

StorageSecurityNotes
httpOnly cookieHighestNot accessible to JavaScript — protects against XSS. Requires same-site or CORS setup.
sessionStorageMediumCleared when tab closes. Vulnerable to XSS.
localStorageMediumPersists across sessions. Vulnerable to XSS.
URL fragment / query stringLowestNever 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-keychain or 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.