AMD AI Workbench authentication session OAuth refresh token

Session Lifetime#

This page applies to interactive user sessions that obtain tokens through the Keycloak authentication flow. For longer-lived programmatic credentials used by applications and unattended scripts, see API Keys for Programmatic Access instead.

Default Lifetimes#

The shipped realm configuration uses these defaults:

  • Access token lifespan: 300 seconds (5 minutes)

  • SSO session idle timeout (refresh-token idle): 1800 seconds (30 minutes)

  • SSO session max lifespan (absolute cap): 36000 seconds (10 hours)

The refresh_expires_in value returned by Keycloak on each token response is the smaller of the remaining idle window and the remaining max-lifespan window, so it shrinks as the session ages.

These are the shipped defaults from the realm configuration and may differ per deployment.

Refreshing an Access Token#

To refresh an access token before it expires, POST to the Keycloak token endpoint with Content-Type: application/x-www-form-urlencoded and the form fields client_id, grant_type=refresh_token, and refresh_token. Confidential clients must also send client_secret; public clients (including typical PKCE clients) omit it.

The realm name is deployment-specific (often airm) — confirm yours with your platform administrator and substitute it for ${REALM} below.

curl Example#

curl -X POST "${KEYCLOAK_BASE_URL}/realms/${REALM}/protocol/openid-connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=${CLIENT_ID}" \
  -d "client_secret=${CLIENT_SECRET}" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=${REFRESH_TOKEN}"

Omit the client_secret line for public clients.

Python Example#

import requests
import os

data = {
    "client_id": os.environ["CLIENT_ID"],
    "grant_type": "refresh_token",
    "refresh_token": os.environ["REFRESH_TOKEN"],
}
# Confidential clients only — public/PKCE clients have no secret.
if "CLIENT_SECRET" in os.environ:
    data["client_secret"] = os.environ["CLIENT_SECRET"]

response = requests.post(
    f"{os.environ['KEYCLOAK_BASE_URL']}/realms/{os.environ['KEYCLOAK_REALM']}/protocol/openid-connect/token",
    data=data,
)
response.raise_for_status()
tokens = response.json()

Successful Response#

A successful refresh returns HTTP 200 with a JSON body:

{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "expires_in": 300,
  "refresh_token": "eyJhbGciOiJIUzUxMiIs...",
  "refresh_expires_in": 1800,
  "token_type": "Bearer",
  "scope": "openid profile email"
}

Expiry Behavior#

When Your Access Token Has Expired#

The AIWB API responds with HTTP 401 and body:

{"detail": "Token expired"}

Companion 401 responses you may encounter for related conditions:

  • Missing Authorization header: {"detail": "Unauthorized"} (returned with WWW-Authenticate: Bearer)

  • Malformed or otherwise invalid token: {"detail": "Validation of token failed: <reason>"}

When Your Refresh Token Has Expired#

The Keycloak token endpoint responds with HTTP 400:

{"error": "invalid_grant", "error_description": "Token is not active"}

The client must restart the authentication flow to obtain a fresh token pair.

Operator-Tunable Defaults, Not an SLO#

The lifetimes above are realm settings on the Keycloak server, configurable by your platform administrator. The shape of the flow (response codes, refresh semantics) is stable; the exact numbers may differ per deployment. If precise lifetimes matter for your automation, read expires_in and refresh_expires_in from each token response or confirm the deployed values with your administrator.

When to Use API Keys Instead#

For programmatic or unattended traffic, prefer API Keys for Programmatic Access over the user-session refresh flow.