Skip to main content

Token format reference

This page describes the structure of Ory Talos API keys, imported keys, and derived tokens, and how Ory Talos routes a submitted credential to the correct verification path.

API key format

Generated API keys use a versioned format:

<prefix>_v1_<identifier>_<checksum>

Example:

prod_v1_QixobFgVufjZNuoYXKtn78NAqFVroyN518nRaK3WD3nxTNufzwJq9sjdrDMrcyP2_3wyBJBd2KxqXK117oqGWZzJU85Nv7C9vKWj9nVSqbEby

Components

ComponentLengthDescription
prefix1-16 charsUser-defined label (for example, prod, dev, test). Set via credentials.api_keys.prefix.current in config.
v12 charsFormat version identifier
identifier~64 charsBase58-encoded timestamp:uuid payload
checksum~44 charsFull 32-byte HMAC-SHA256 over prefix_v1_identifier_, Base58-encoded

Identifier encoding

The identifier is the Base58 encoding of timestamp:uuid:

  • Timestamp: Unix epoch seconds (int64), set at key creation time.
  • UUID: UUID v4 (36 chars with hyphens). Used as the key_id for database lookup.

Base58 uses the Bitcoin alphabet (123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz), which omits the visually ambiguous characters 0, O, I, and l.

Checksum verification

The checksum is computed over the payload prefix_v1_identifier_:

  1. Compute HMAC-SHA256 with the current HMAC secret (secrets.hmac.current).
  2. Base58-encode the full 32-byte digest (no truncation).

During verification, Ory Talos tries all configured secrets in order, current (secrets.hmac.current) first, then retired (secrets.hmac.retired). This supports secret rotation without invalidating existing keys.

Credential routing

When a credential is submitted for verification, Ory Talos checks its format in this order and stops at the first match:

OrderFormat matchCredential typeLookup method
1JWT format (eyJ...)Derived JWTClaims extracted during verification
2Token starts with a configured macaroon prefix followed by _v1_ (credentials.derived_tokens.macaroon.prefix.current or retired)Derived macaroonIdentifier extracted during verification
3<prefix>_v1_<id>_<checksum> matches the API key shapeGenerated API keyUUID extracted from identifier
4None of the aboveImported keySHA-512/256 hash with tenant scope

Macaroons share the <prefix>_v1_... shape with generated API keys; routing distinguishes them by checking the configured macaroon-prefix list before falling through to the API key regex.

Imported key format

Imported keys have no format requirements: any string credential can be imported. Ory Talos stores a tenant-scoped hash instead of the raw key:

SHA-512/256(network_id + 0x00 + raw_key)

The null-byte separator prevents ambiguity between the network ID and the key content. Including the network ID in the hash input makes the same raw key resolve to a different hash in each tenant.

Derived token formats

JWT

Derived tokens produced as JWTs follow the standard JWT format:

eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature

The sub claim holds the parent key's ID. Other claims include act (actor ID), scp (scopes), and exp (expiration). The signing algorithm follows the JWK key type: Ed25519 keys produce EdDSA signatures, RSA keys produce RS256. The alg header on the issued JWT reflects this choice.

Signing key selection (kid hint)

Ory Talos resolves the active signing key on every derive request. The kid header in the issued JWT identifies which JWK from the configured JWKS produced the signature.

Resolution order:

  1. If credentials.derived_tokens.jwt.signing_key_id is set, Ory Talos selects the JWK whose kid matches. If no JWK has that kid, signing fails with InternalError, and the error details include the requested signing_key_id.
  2. Otherwise, Ory Talos selects the first key with "use": "sig".
  3. Otherwise, Ory Talos selects the first key in the JWKS.

Set signing_key_id explicitly in production so that rotating signing material is a config change rather than a side effect of JWKS ordering. In multi-tenant deployments, the JWKS resolves per tenant through the contextualizer, so the kid hint is also per-tenant.

Macaroon

Macaroon tokens use a configurable prefix:

<prefix>_v1_<base64url_data>

Set the prefix with credentials.derived_tokens.macaroon.prefix.current (default: mc, 1-8 alphanumeric characters or underscores). The data section is the base64url-encoded binary macaroon: its identifier, location, JSON caveat (the claims), and signature.

ID formats

ContextFormatLengthExample
Database storageUUID v4 string36 chars550e8400-e29b-41d4-a716-446655440000
API key identifierBase58-encoded~64 charsQixobFgVufjZNuoYXKtn78NAqFVroyN518nRaK3WD3nxTNufzwJq9sjdrDMrcyP2
Imported key hashHex-encoded SHA-512/25664 charsa1b2c3d4...