Skip to main content

Map identities to Virtual Keys

Enterprise feature

JWT authentication requires a LiteLLM Enterprise license. Start a free 30-day trial or book a demo. See what Enterprise includes.

Let a client authenticate with an identity-provider JWT in place of a static LiteLLM credential. Map a stable JWT claim to an existing virtual key, then send the JWT as the bearer token.

How it works​

LiteLLM validates the JWT using your configured signing keys, issuer, and audience, then looks up the configured claim. A matching mapping identifies the virtual key used for authorization and usage tracking. Configure that key's permissions through Access Management.

If no mapping exists, unregistered_jwt_client_behavior determines whether to reject the request, use standard JWT authorization, create a key, or link an existing one.

Prerequisites​

Complete identity provider setup and connect your proxy to a database. Have an existing virtual key ready with the caller's required LLM, MCP, or agent access. See Virtual Keys for key creation and settings.

The test request below uses a configured model named my-model that the key can access.

Choose a stable claim that identifies the caller. Use sub for a person or a provider's application identifier for a workload. A shared application client_id does not distinguish individual users.

Mapping administration requires a proxy admin or admin viewer, depending on the operation.

Setup​

1. Configure the mapping claim​

Add these settings to your existing proxy configuration. This example requires an administrator to register each mapping.

general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
database_url: os.environ/DATABASE_URL
enable_jwt_auth: true
litellm_jwtauth:
user_id_jwt_field: sub
virtual_key_claim_field: sub
unregistered_jwt_client_behavior: reject

2. Register a mapping​

Register the existing key against the caller's claim value. The claim name must match virtual_key_claim_field, and the value must match the caller's JWT.

curl -X POST 'http://localhost:4000/jwt/key/mapping/new' \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H 'Content-Type: application/json' \
-d '{
"jwt_claim_name": "sub",
"jwt_claim_value": "user-123",
"key": "<existing-virtual-key>",
"description": "user-123"
}'

Creating a mapping does not create or change the key.

Map with the key's hash instead of the plaintext key​

Since v1.104.0

If you no longer have the plaintext key, pass its SHA-256 hash as token. Use the token returned by /key/generate, or the key hash returned by /key/list. Send exactly one of key or token; sending a hash as key hashes it again and returns The provided key does not match an existing virtual key.

curl -X POST 'http://localhost:4000/jwt/key/mapping/new' \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H 'Content-Type: application/json' \
-d '{
"jwt_claim_name": "sub",
"jwt_claim_value": "user-123",
"token": "<64-character lowercase hex key hash>",
"description": "user-123"
}'

Test authentication​

Obtain a JWT from your identity provider with sub: user-123, and send it as the bearer token.

export JWT_TOKEN="<identity-provider-jwt>"

curl 'http://localhost:4000/v1/chat/completions' \
-H "Authorization: Bearer $JWT_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"model": "my-model",
"messages": [{"role": "user", "content": "Hello"}]
}'

The request uses the linked key's existing permissions. View its usage in the dashboard or through /key/info.

Configuration reference​

Mapping claim and cache​

virtual_key_claim_field supports nested claims such as user.sub. Its previous name, jwt_client_id_field, remains an alias. virtual_key_mapping_cache_ttl sets the mapping cache lifetime in seconds and defaults to 300.

unregistered_jwt_client_behaviorWhen no mapping exists
fallback_team_mappingUse standard JWT authorization. This is the default.
rejectReturn 403.
auto_registerCreate a virtual key and mapping after JWT authorization. Optionally try an existing key first.
link_onlyLink an eligible existing user key, or return 403. Never create a key.

A missing claim also returns 403 in reject, auto_register, and link_only modes.

Create mappings automatically​

Set unregistered_jwt_client_behavior: auto_register to create a key and mapping on the first request from an unmapped identity. Configure the user, team, and organization claims you want the new key to inherit using the identity claim settings.

Before creating anything, LiteLLM runs JWT authorization, including configured role and scope checks, custom_validate, and email-domain restrictions. The new key inherits the resolved identity. Use manual mapping when administrators must configure the key before its first request; see Access Management.

Set auto_register_map_existing_key: true to reuse an eligible user key first and create a new one only if none exists. For reuse, virtual_key_claim_field must match user_id_jwt_field or user_email_jwt_field. A database connection is required. Unmapped proxy-admin JWTs authenticate directly without creating a mapping.

Since v1.109.0

Use link_only when administrators provision keys ahead of time. The first authorized request links the identity to its newest eligible key. If no key qualifies, LiteLLM returns 403 with JWT Key Mapping: No eligible existing virtual key for this identity. Access denied.

general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
database_url: os.environ/DATABASE_URL
enable_jwt_auth: true
litellm_jwtauth:
user_id_jwt_field: sub
virtual_key_claim_field: sub
user_id_upsert: false
unregistered_jwt_client_behavior: link_only

The mapping claim must match user_id_jwt_field or user_email_jwt_field, and the database must be connected. This mode never creates keys. user_id_upsert: true can still create users, so keep it false if users must already exist. Unmapped proxy-admin JWTs authenticate directly without linking a key.

Which existing key is selected​

For link_only and auto_register_map_existing_key, the key must belong to the resolved user and team, or have no team when the JWT resolves none. It must never expire, must not be blocked, and must not be an Admin UI session key or an auto-registered key. The newest eligible key wins. Later requests keep that mapping even if a newer key is created.

allowed_routes does not affect selection. Review the existing key's permissions before enabling automatic linking, including any management-route permissions it grants.

Multiple identity providers​

Configure issuer-bound validation with litellm_jwtauth.issuers in the per-issuer configuration, then set jwt_issuer on each mapping to the corresponding configured issuer. Issuer-specific virtual_key_claim_field and unregistered_jwt_client_behavior settings can override the global values.

{
"jwt_issuer": "https://idp.example.com",
"jwt_claim_name": "sub",
"jwt_claim_value": "user-123",
"key": "<existing-virtual-key>"
}

LiteLLM first looks for an issuer-scoped mapping, then falls back to a global mapping without jwt_issuer. Global mappings share the same claim namespace across providers. Use issuer-scoped mappings to distinguish identical claim values from different providers.

Manage mappings​

Mapping responses include an id, claim name and value, issuer, description, active flag, and audit metadata. They never return the linked key or its hash. Manage the key itself through Virtual Keys.

OperationEndpointInput
ListGET /jwt/key/mapping/listpage and size query parameters
InspectGET /jwt/key/mapping/infoid query parameter
UpdatePOST /jwt/key/mapping/updateJSON id plus key or token, description, is_active, or jwt_issuer
DeletePOST /jwt/key/mapping/deleteJSON id

For example, list mappings to find an ID, then point that mapping to a replacement key.

curl 'http://localhost:4000/jwt/key/mapping/list?page=1&size=50' \
-H "Authorization: Bearer $LITELLM_MASTER_KEY"

curl -X POST 'http://localhost:4000/jwt/key/mapping/update' \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H 'Content-Type: application/json' \
-d '{"id": "<mapping-id>", "key": "<replacement-key>"}'

See mapping-management permissions for the roles allowed to perform each operation.

Troubleshooting​

CodeMeaning
400Invalid key identifier or key not found.
403Unmapped identity denied by policy, no eligible existing key, or insufficient mapping-management permissions.
404Mapping not found.
409A mapping already exists for that issuer, claim name, and claim value.

For signature, issuer, audience, or signing-key errors, see JWT troubleshooting. If a mapped credential is accepted but its resource request is denied, check the linked key's permissions in Access Management.

Use identity provider setup to configure token verification, or map identities to users and teams to resolve the caller directly. See Virtual Keys to manage the linked credential and JWT permissions for mapping-management roles and policy behavior.

For Claude Code client configuration, see Use an identity-provider token.