Skip to main content

Agent Authentication

An agent occupies multiple identity postures simultaneously, and each posture requires a different authentication pattern.

  • Agent as subject: the agent authenticates as itself to call APIs on its own behalf. Use the M2M (client credentials) pattern.
  • Agent as actor: the agent carries delegated authority on behalf of a user or another principal. Use the OBO (token exchange) pattern. The access the agent carries can never exceed the authority that was delegated to it.

Both patterns use the token endpoint at POST /oauth2/token. The agent must be registered with an OAuth inbound auth config before it can request tokens.

M2M Tokens (Agent as Subject)

Use M2M tokens in the subject posture: the agent calls APIs on its own behalf with no user involved. Common cases: background jobs, data pipelines, service-to-service calls.

Request a Token

curl -X POST https://localhost:8090/oauth2/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-u '<CLIENT_ID>:<CLIENT_SECRET>' \
-d 'grant_type=client_credentials' \
-d 'resource=https://api.example.com/invoices'

Request Specific Scopes

ThunderID intersects the requested scopes against the target resource server's permissions and the scopes authorized for the agent via its group memberships and role assignments. Scopes outside that intersection are omitted from the issued token.

curl -X POST https://localhost:8090/oauth2/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-u '<CLIENT_ID>:<CLIENT_SECRET>' \
-d 'grant_type=client_credentials' \
-d 'resource=https://api.example.com/invoices' \
-d 'scope=invoices:read invoices:write'

Group membership is evaluated transitively: if the agent is a member of a group that inherits permissions from a parent group, those permissions are included.

Narrow to a Specific Resource Server

Use the resource parameter (RFC 8707) to restrict the token's audience and scopes to a single resource server. This is the recommended approach when the agent calls multiple downstream APIs.

curl -X POST https://localhost:8090/oauth2/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-u '<CLIENT_ID>:<CLIENT_SECRET>' \
-d 'grant_type=client_credentials' \
-d 'resource=https://api.example.com/invoices' \
-d 'scope=invoices:read'

ThunderID resolves the resource identifier against registered resource servers and narrows the token's scopes to only those defined for that resource. Unrecognized resource identifiers return invalid_target.

OBO Tokens (Agent as Actor)

Use OBO tokens in the actor posture: the agent carries delegated authority from a user to a downstream service. The agent can never hold more authority than the principal that empowered it: the issued token's scopes are strictly bounded by what the user's token already contained.

ThunderID implements RFC 8693 token exchange.

Request an OBO Token

The agent presents the user's access token as the subject_token and authenticates itself with its own credentials.

curl -X POST https://localhost:8090/oauth2/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-u '<AGENT_CLIENT_ID>:<AGENT_CLIENT_SECRET>' \
-d 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
-d 'subject_token=<USER_ACCESS_TOKEN>' \
-d 'subject_token_type=urn:ietf:params:oauth:token-type:jwt' \
-d 'resource=https://api.example.com/invoices'

The issued token represents the agent acting on behalf of the user. Its scopes are bounded by the scopes present in the subject_token, the permissions defined by the target resource server, and the permissions assigned to the issuing agent.

Request a Constrained Scope

Pass a scope parameter to request a subset of the user's scopes. ThunderID rejects any scope that is not already in the subject_token.

curl -X POST https://localhost:8090/oauth2/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-u '<AGENT_CLIENT_ID>:<AGENT_CLIENT_SECRET>' \
-d 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
-d 'subject_token=<USER_ACCESS_TOKEN>' \
-d 'subject_token_type=urn:ietf:params:oauth:token-type:jwt' \
-d 'resource=https://api.example.com/invoices' \
-d 'scope=invoices:read'

Target a Resource Server

Use resource (RFC 8707) for the resource server URI:

  -d 'resource=https://api.example.com/invoices'

The RFC 8693 audience parameter is accepted for compatibility but does not determine the access token's aud claim. For permission-bearing requests, the access-token audience is the resolved resource, or the configured defaultResourceServer when resource is omitted. An OIDC-only or scopeless request without resource uses the agent's default audience (token.accessToken.defaultAudience), or the client_id when it is unset.

Token Characteristics

All agent access tokens are signed JWTs (typ: at+jwt) and share a common set of claims. The value of some claims differs by grant type.

ClaimM2M (client_credentials)OBO (token exchange)
subThe agent's resource ID.The original user's subject identifier.
issThunderID instance URL.ThunderID instance URL.
audThe resolved resource server identifier, or the default audience (falling back to Client ID) for a scopeless request without resource.The resolved resource server identifier, or the default audience (falling back to Client ID) when no permission scopes or resource are present.
scopeAuthorized scopes from the agent's group/role assignments.A subset of the user's original scopes.
client_idThe agent's Client ID.The agent's Client ID.
grant_typeclient_credentialsurn:ietf:params:oauth:grant-type:token-exchange
actNot present.Present only when an explicit actor_token is provided in the request.
exp, iat, nbf, jtiStandard JWT lifetime and identity claims.Standard JWT lifetime and identity claims.

Custom attributes configured in the agent's Token settings are included as additional claims on M2M tokens.

act Claim

When a token exchange request includes an explicit actor_token, the issued OBO token contains an act object identifying the actor:

"act": {
"sub": "<ACTOR_RESOURCE_ID>",
"iss": "<ISSUER>"
}

If the actor token itself carries an act claim (a chained delegation), that claim nests inside the new act object, preserving the full delegation chain.

Use the Token to Call a Protected API

Both M2M and OBO tokens are Bearer tokens. Pass the token in the Authorization header:

curl https://api.example.com/invoices \
-H 'Authorization: Bearer <ACCESS_TOKEN>'

Your resource server should validate:

ClaimWhat to verify
expToken has not expired.
issMatches your ThunderID instance URL.
audMatches your resource server identifier.
scopeIncludes the scope required for the operation.

Use the ThunderID JWKS endpoint to retrieve public keys for signature verification:

curl https://localhost:8090/oauth2/jwks

Refresh Tokens

Agents using the authorization code grant receive refresh tokens to maintain long-lived sessions without requiring the user to re-authenticate.

curl -X POST https://localhost:8090/oauth2/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-u '<CLIENT_ID>:<CLIENT_SECRET>' \
-d 'grant_type=refresh_token' \
-d 'refresh_token=<REFRESH_TOKEN>'

Scopes on the new access token are bounded by the scopes of the original grant. You can request a narrower scope with the scope parameter; requesting a broader scope returns invalid_scope.

Refresh tokens preserve the resource server binding from the original grant. A refresh request may repeat the same resource, or omit it to keep the existing binding.

Troubleshooting

ErrorLikely Cause
invalid_clientWrong CLIENT_ID or CLIENT_SECRET. Verify credentials and ensure the agent has an OAuth config.
invalid_scopeThe agent is not authorized for the requested scope. Check the agent's group and role assignments.
invalid_grantThe grant type is not in the agent's configured grantTypes.
invalid_targetThe resource value does not match a registered resource server.
Token accepted but API returns 403Token scope or audience does not meet the resource server's policy.

Next Steps

  • Manage Agents: Configure OAuth credentials, assign groups, and rotate secrets.
  • Resource Servers: Register resource servers and define the scopes they accept.
  • Resource Indicators: Use RFC 8707 resource parameters to issue audience-restricted tokens.

Explore with AI

ThunderID LogoThunderID Logo

Product

DocsAPIsSDKs
© Copyright Linux Foundation Europe.For web site terms of use, trademark policy and other project policies please see https://linuxfoundation.eu/en/policies.