OAuth 2.0 Token Exchange

Modern deployments rarely consist of a single service that consumes an access token and answers the caller directly. A request that enters the landscape at an API gateway is typically served by a chain of backend services, each of which needs a token that is scoped to itself rather than the token that the original client presented. Passing the original token along the chain is convenient but violates the principle of least privilege: every hop receives a credential that is valid for every other hop.

OAuth 2.0 Token Exchange, defined in RFC8693: OAuth 2.0 Token Exchange, solves this problem. It defines a token endpoint grant type that lets a client present a security token it already holds and receive a new security token in return — one that is issued for a different audience, carries a reduced set of scopes, and records who is acting on whose behalf.

DirX Access implements this specification as an extension of its OAuth 2.0 Authorization Framework support. Everything described in OAuth 2.0 Authorization Framework — client authentication, token representation, JWT access tokens, attribute templates, and the OAuth Server / OAuth Provider component split — also applies to token exchange. This document describes only what is specific to the token exchange grant type.

Concepts

Token exchange distinguishes three parties.

Subject

The principal on whose behalf the exchanged token is issued. It is identified by the subject token passed in the request and it becomes the sub claim of the issued token.

Actor

The principal that acts on the subject’s behalf. It is identified by the actor token or — when no actor token is presented — derived from the requesting OAuth client. It becomes the act claim of the issued token.

Target audience

The service the issued token is intended for. It becomes the aud claim of the issued token and it is the key that drives both configuration routing and the authorization decision on the requested scopes.

The relation between the subject and the actor determines the exchange mode:

  • Impersonation — the issued token names only the subject. The downstream service cannot tell that the token was obtained by exchange; the actor disappears.

  • Delegation — the issued token names the subject in sub and the actor in act. The downstream service sees both principals and can apply policies that depend on the acting party. Delegation chains nest: exchanging an already delegated token places the previous act value inside the new one as act.act.

Because impersonation removes all traces of the acting party, it is the more powerful and therefore the more sensitive of the two modes. DirX Access lets you control precisely when each mode may be used.

Design

Token exchange is processed by the token endpoint of the OAuth Server. A request carrying grant_type=urn:ietf:params:oauth:grant-type:token-exchange is branched off into a dedicated processing chain that performs the following steps in order:

  1. Configuration routing. The request is matched against the configured token exchange configuration items and exactly one of them is selected. All subsequent steps are governed by the selected item. See Determining Parameters.

  2. Client authentication. The client identified by client_id is resolved and, unless it is a public client, authenticated by client_secret. The supported client authentication methods are client_secret_basic, client_secret_post and none. Communication with unregistered clients is not supported. A client that presents no credentials is admitted only if Do public client support for token endpoint is enabled on the selected configuration item; in that case the client is identified but not authenticated, and the authorization policies can tell the difference (see Available Token Exchange Attributes).

  3. Subject and actor resolution. The subject token and, if present, the actor token are validated and — depending on who issued them — resolved into DirX Access subjects. See Subject and Actor Resolution.

  4. Exchange mode resolution. Impersonation or delegation is decided, including the may_act checks and the optional downgrade to impersonation. See Exchange Mode.

  5. Target audience resolution. The audience and resource request parameters are resolved into a set of audience URIs. See Target Audience Resolution.

  6. Scope evaluation. Each requested scope is authorized against each resolved target audience by a Policy Decision Point. See Token Exchange Scope Evaluation.

  7. Token issuance. The token of the requested type is created, its lifetime is capped, and its claims are assembled from the built-in sources and from the configured attribute templates. See Lifetime of the Issued Token and Claims of the Issued Token.

A failure in any of these steps terminates the request with an OAuth error response; no token is issued. The presented subject token and actor token are never consumed or invalidated by the exchange — they remain valid for their original lifetime and can be exchanged repeatedly.

The Token Exchange Request

The token exchange request is a normal token endpoint request. The following parameters are relevant.

Parameter Description

grant_type

Must be urn:ietf:params:oauth:grant-type:token-exchange.

subject_token

The token representing the principal on whose behalf the new token is requested. Mandatory.

subject_token_type

The type URI of the subject token. Mandatory, and it must correspond to the token actually presented.

actor_token

The token representing the acting party. Optional; if present, actor_token_type must be present as well.

actor_token_type

The type URI of the actor token. Must not be present without actor_token.

requested_token_type

The type URI of the token to be issued. Optional; when absent, the Default requested token type of the selected configuration item applies.

audience

The logical name(s) of the target service(s). Resolved to audience URIs through the Audience name mapping.

resource

The absolute URI(s) of the target service(s). URIs containing a fragment component are rejected.

scope

The requested scopes. When absent, the scopes carried by the subject token are requested instead.

Both audience and resource may be repeated and may be combined in a single request; together they form the set of target audiences of the exchange.

A successful response is a token endpoint response containing access_token (which carries the issued token regardless of its type), issued_token_type, token_type, expires_in and, where applicable, scope.

Supported Token Type Combinations

RFC8693 defines the token type URIs urn:ietf:params:oauth:token-type:access_token, urn:ietf:params:oauth:token-type:id_token and urn:ietf:params:oauth:token-type:refresh_token. DirX Access does not currently implement every combination of them. The token types of a request are validated as a triple, and only the following combinations are accepted:

subject_token_type actor_token_type requested_token_type Result

access_token

absent

absent

A token of the type given by Default requested token type.

access_token

absent

access_token

An access token, in impersonation or delegation mode according to Delegation without actor token mode.

access_token

absent

id_token

An ID token, in impersonation or delegation mode according to Delegation without actor token mode.

access_token

access_token

absent

A token of the type given by Default requested token type, with the actor taken from the actor token.

access_token

access_token

access_token

An access token, with the actor taken from the actor token.

access_token

access_token

id_token

An ID token, with the actor taken from the actor token.

In other words, in the current version:

  • The subject token must be an access token.

  • An actor token, if present, must be an access token.

  • The requested token may be an access token or an ID token. Requesting a refresh token is not supported.

Support for ID tokens as actor tokens and for refresh tokens as the requested token type is planned for a future version.

A request that names a token type URI the server does not know, or a combination that is not in the table above, is rejected with invalid_request. An unsupported token type is never folded into “unspecified”: it is reported as an error rather than silently processed as if the parameter had been omitted.

The Subject token type, Actor token type and Requested token type determining parameters offer all three token type URIs for selection, including those that no supported combination uses. Selecting such a value does not extend what the server can do — it only routes the affected requests to that exchange profile, which then rejects them with invalid_request.

Configuration

Token exchange is configured on the Authorization and token endpoints of the OAuth Server Endpoint. A configuration item becomes a token exchange configuration item — in the remainder of this document called an exchange profile — as soon as urn:ietf:params:oauth:grant-type:token-exchange is among its Grant types. DirX Access Manager then reveals the token-exchange-specific configuration elements described in the following sections.

For token exchange to be useful, the OAuth Server should also have the JWT format enabled for its access tokens, so that the exchanged token can carry the sub, act, aud and scope information to the downstream service without an introspection round trip.

An OAuth Server may hold any number of exchange profiles. This is the mechanism by which a single OAuth Server can offer different token exchange behaviour to different clients, for different source tokens, and for different target services.

Determining Parameters

The determining parameters decide which exchange profile applies to an incoming request, and consequently whether the feature is accessible to a given caller at all. Routing is the very first step of the exchange: it precedes client authentication and the validation of the presented tokens, so a request that matches no exchange profile is rejected before any credential is verified and before any policy is evaluated. To make this possible, the routing reads the request as it is stated — the client_id the caller claims, and the claims the presented tokens assert — and canonicalizes the target audiences; it verifies nothing itself.

Determining parameters are a routing mechanism, not a verification mechanism. A claim criterion over a subject token claim selects the profile that will govern the exchange, but the signature, validity and issuer of that token are established afterwards, by the subject resolution described in Subject and Actor Resolution. Likewise, a claim criterion over the client selects a profile by the stated client_id, which the client authentication step then has to substantiate. Routing therefore determines which rules a request is judged by; it never substitutes for those rules. Anything that must hold for the token to be issued belongs additionally in the scope evaluation policy described in Token Exchange Scope Evaluation, which runs on verified data.

The following configuration elements are determining parameters:

Subject token type

The subject_token_type values the profile applies to. An empty selection matches any subject token type.

Actor token type

The actor_token_type values the profile applies to. An empty selection matches any actor token type.

Requested token type

The requested_token_type values the profile applies to. An empty selection matches any requested token type.

These three elements select which requests a profile is responsible for; they do not extend what the server can process. See Supported Token Type Combinations.
Target audience

A condition on the resolved target audiences, expressed in Disjunctive Normal Form.

Requested scope predicates

A condition on the requested scopes, expressed in Disjunctive Normal Form.

Claim criteria

A list of (source, claim name, expression) triples. The source is the subject token, the actor token, or the authenticated client; the expression is a condition in Disjunctive Normal Form on the values the named claim resolves to. Claim criteria are the general-purpose routing dimension: they can address the issuer of the source token (iss), the audience the source token was issued for (aud), the scopes it carries (scope), the identity of the requesting client (client_id), or any custom claim. All configured criteria must be satisfied.

Disjunctive Normal Form Conditions

Target audience, Requested scope predicates and the expression of a Claim criterion share the same condition syntax. A condition is a disjunction of conjunctions, written in DirX Access Manager as (A^B) v (C^D)*. Outside DirX Access Manager, conjunctions are written as comma-separated parenthesized groups, for example (A,B,C),(D).

  • A plain conjunction matches only if the actual values are exactly its values.

  • An open-ended conjunction, marked by a trailing , matches whenever the actual values *contain its values; further values are allowed.

  • A condition left blank matches any value, including none.

  • The condition () matches an empty set of values.

The difference between plain and open-ended matching is what makes these conditions usable for restricting access. (read) grants a profile only to requests that ask for exactly the read scope, whereas (read)* also admits a request asking for read write delete.

Profile Selection

An exchange profile is applicable to a request only if every determining parameter it configures is satisfied. Determining parameters that are left empty do not restrict the profile.

If no applicable profile is found, the request fails with invalid_target and the description No matching exchange profile. This makes the determining parameters the primary tool for limiting the availability of the feature. Typical patterns are:

  • Restricting the callers by a claim criterion on the client, for example (CLIENT, client_id, (api-gateway)).

  • Restricting the accepted source tokens by a claim criterion on the subject token issuer, for example (SUBJECT_TOKEN, iss, (https://login.example.com)).

  • Restricting the reachable services with Target audience.

  • Preventing privilege escalation by requiring the source token to already carry the requested scopes with a claim criterion such as (SUBJECT_TOKEN, scope, (read)*).

  • Restricting the kind of token that may be issued with Requested token type, for example admitting only access_token so that a profile cannot be used to obtain an ID token.

Subject and Actor Resolution

The subject token and the actor token must be validated before the exchange can proceed, and — where the OAuth Server is in a position to do so — mapped onto a DirX Access subject. Both tokens are handled identically and independently of each other; the description below applies to each of them.

A presented token must be a signed JWT carrying an iss claim, and it must not be a refresh token. Its iss claim, compared with the issuer of this OAuth Server and with the audience the token was issued for, selects one of three resolution paths. Validation happens on all three; a DirX Access subject is produced on the first two.

Path 1: The Token Was Issued by This OAuth Server

The iss claim equals the issuer of this OAuth Server. The token is one this OAuth Server minted itself, so its state is known locally:

  1. The signature is verified against this OAuth Server’s own keys.

  2. The token identifier is resolved and the token is looked up in the OAuth Server’s token store. The lookup is non-destructive — the presented token is not consumed and remains usable afterwards. If no entry is found, the token has been revoked or is unknown and the request fails with invalid_grant.

  3. The DirX Access subject is taken from the SSO session that the stored token entry refers to.

This is the path with the strongest guarantees: revocation is honoured immediately, and the resulting subject is the live session subject, so its roles and attributes are current rather than a snapshot taken when the token was issued. The trust path attribute reports SELF_AS.

Path 2: This OAuth Server Is the Audience of the Token

The iss claim names a different issuer, but the aud claim of the token contains this OAuth Server. The token was issued by a federation partner for this OAuth Server, which is therefore its legitimate recipient and can validate it the same way it validates any incoming token addressed to it.

Validation and subject construction are delegated in full to the configured authentication method:

The referenced authentication method performs the signature and claim verification and produces the DirX Access subject, which means the exchange benefits from the full authentication configuration — including the identity mapping the method defines. If the applicable authentication method is not configured, the subject cannot be resolved and the request fails with invalid_grant. The trust path attribute reports THIRD_PARTY.

Path 3: The Token Belongs to an External Audience

The iss claim names a different issuer and the aud claim does not contain this OAuth Server. The token was neither issued by nor addressed to this OAuth Server; it is being routed through it purely to be exchanged. This is the path governed by Trusted issuers for external audience:

  1. The issuer must be listed there. The configuration element references the OAuth Server metadata of the trusted issuers, from which their signing keys are taken. An issuer that is not listed, or whose metadata provides no key set, causes the request to fail with invalid_grant.

  2. The signature is verified against that issuer’s key set.

  3. The exp and nbf claims are checked.

Because the token is not addressed to this OAuth Server, no DirX Access subject is constructed for it. The exchange proceeds on the claims the token asserts alone. The trust path attribute reports THIRD_PARTY.

On this path there is no subject whose roles could be evaluated, so authorization rules that grant scopes on the basis of role assignments cannot match. Exchanges of externally-addressed tokens must be authorized over the token exchange attributes instead — see Available Token Exchange Attributes. Revocation is likewise not visible: the issuer’s key set proves only that the token was signed by that issuer, not that it is still valid at the issuer. Keep Cap to source enabled on such profiles so that the exchanged token cannot outlive the presented one.

Distinguishing the Paths in Policy

The trust path is exposed to the authorization policies as solutions:dirx:access:oauth:token-exchange:trust-path for the subject token and solutions:dirx:access:oauth:token-exchange:actor-trust-path for the actor token, with the values SELF_AS and THIRD_PARTY. A policy that grants sensitive scopes can therefore require SELF_AS, or admit THIRD_PARTY only in combination with further conditions — for instance on the issuer, reachable as the iss claim of the respective token.

Paths 2 and 3 both report THIRD_PARTY. Where they need to be told apart, compare the aud claim of the token, which is available as solutions:dirx:access:oauth:token-exchange:subject-token:claim:aud.

Exchange Mode

The exchange mode is derived from the request and from the exchange profile.

When the request carries an actor token, the mode is governed by:

Delegation with actor token allowed

Whether delegation with an actor token is permitted at all.

Delegation with actor token may act required

Whether the subject token must carry a may_act claim that names the actor. This turns delegation into an opt-in that the subject’s token has to grant, rather than something the acting client can request unilaterally. If the claim is absent or does not match the actor, the request fails with invalid_request.

Delegation with actor token downgrade to impersonation

Whether a request that does not meet the delegation conditions falls back to impersonation instead of being rejected. Whether the downgrade took place is exposed to the authorization policies, so a policy can grant a narrower scope set to downgraded requests.

When the request carries no actor token, the mode is governed by:

Delegation without actor token mode

DELEGATION_CLIENT_AS_ACTOR treats the requesting client as the acting party and issues a delegated token; IMPERSONATION issues an impersonation token for the subject; DENY rejects the request.

Delegation without actor token may act required

Whether the subject token must carry a may_act claim. Offered only when the mode is not DENY.

IMPERSONATION without a may_act requirement means that any client that reaches an exchange profile can obtain a token that is indistinguishable from a token issued directly to the end user. Restrict such profiles tightly with the determining parameters, and use the scope evaluation to bound what the resulting token can be used for.

Target Audience Resolution

The audience and resource request parameters are resolved into the set of audience URIs that the issued token is bound to:

  • resource values are absolute URIs and are used as they are. A resource value containing a fragment is rejected with invalid_request.

  • audience values are logical names and are translated through Audience name mapping, which maps a logical name onto an audience URI. This decouples the clients from the deployment topology: a client asks for token-exchange-backend and does not need to know that this currently resolves to https://backend.acme.example/api.

  • If the request contains neither parameter, the Default target audience applies.

An audience value that has no mapping, or a target that is not a trusted peer, results in invalid_target.

Multiple Target Audiences

A single request may name several target audiences. Since scopes are authorized per audience (see Token Exchange Scope Evaluation), the audiences may well yield different effective scopes, and Multi-audience strategy decides how such a divergence is reconciled:

Value Behaviour

INTERSECT_SCOPES

All requested audiences are kept and the issued token carries the intersection of their effective scopes. Choose this when the client needs one token that works everywhere, and a smaller scope set is acceptable.

FILTER_AUDIENCES

The maximal scope set is kept and the audiences that would narrow it are dropped from the issued token. Choose this when the scope set matters more than reaching every named service.

REQUIRE_UNIFORM

All audiences must yield the same effective scope; otherwise the request is rejected. Choose this when a partial result would be a configuration error rather than a legitimate outcome.

If filtering leaves no audience at all, the request fails with invalid_target and the description No valid target audience after scope evaluation.

Lifetime of the Issued Token

The lifetime of the exchanged token is the minimum of several bounds:

  • The access token validity of the exchange profile, as for any other grant type.

  • Maximum lifetime, an upper bound in seconds specific to token exchange. The value 0 means that no additional upper bound is imposed. Note that this element can only shorten the lifetime, never extend it beyond the access token validity of the profile.

  • The remaining lifetime of the subject token, if Cap to source is enabled.

Capping to the source is the safer default for delegation chains: without it, each exchange restarts the clock and a short-lived front-end token can be laundered into an arbitrarily long-lived backend token.

Token Exchange Scope Evaluation

Determining parameters decide whether an exchange may happen at all. Scope evaluation decides what the resulting token may do. It is the authorization gate of the token exchange feature, and it is driven by the regular DirX Access policy machinery rather than by a token-exchange-specific rule language.

The gate is opened by the Token Exchange PEP configuration element, which references a Policy Enforcement Point — typically an Other PEP — and through it a Policy Decision Point.

If Token Exchange PEP is left empty, no scope evaluation takes place and every requested scope is granted. A profile without a PEP relies entirely on its determining parameters for containment.

How the Decision Is Made

For each resolved target audience, DirX Access asks the PDP one question per requested scope:

  • The resource of the question is the target audience URI.

  • The action of the question is the scope.

All questions for one audience are issued as a single XACML 3.0 multi-request, so a request asking for three scopes against two audiences costs two PDP invocations, not six. A scope is granted for an audience if and only if the PDP returns Permit for it.

A response in which no scope is permitted is a complete and valid decision: it yields an empty effective scope, not an error. Only a failure of the evaluation itself — the PDP being unreachable or returning an unusable response — is treated as a denial, in which case the request fails with invalid_scope.

What happens to a partial result is decided by Scope resolution strategy:

Value Behaviour

FILTERED

The effective scope may be any subset of the requested scope, including the empty set. The token is issued with what was granted.

EMPTY_TO_ERROR

Filtering is allowed, but an empty effective scope rejects the request with invalid_scope.

EXACT

Every requested scope must be granted; the request is rejected with invalid_scope if any is missing.

FILTERED follows the OAuth convention that the authorization server may issue a token with a narrower scope than requested, and it requires clients to inspect the scope field of the response. EXACT is appropriate when a partially scoped token would be useless to the client anyway and failing fast is preferable.

Configuring the Policy Without a Policy Information Point

In its simplest form the policy is plain RBAC and needs no token-exchange-specific PDP configuration at all, because the question the PDP is asked is already expressed in terms it natively understands: the target audience is the resource, and the scope is the action.

  1. Create an Other PEP for token exchange and reference it from Token Exchange PEP.

  2. For every target service, create a Resource whose Path is the target audience URI and whose PEP identifier is that PEP.

  3. For every scope, create an Action whose key is the scope name.

  4. Create an Authorization Rule combining those resources and actions, and assign it to the Authorization Policy of the roles that are allowed to obtain such a token.

The subject of the authorization request is the subject of the exchange — the principal identified by the subject token. Role-based rules therefore express directly which end users' tokens may be exchanged for which scopes at which service.

The following excerpt shows the shape of such a configuration.

{
  "@odata.type": "#net.atos.dirx.access.apprepo.api.config.policy.resource.Resource",
  "key": "TE Backend Acme resource uri",
  "pepId": { "key": "OAuth Token Exchange",
             "type": "net.atos.dirx.access.apprepo.api.config.client.OtherPep" },
  "path": "https://backend.acme.example/api"
}
{
  "@odata.type": "#net.atos.dirx.access.apprepo.api.config.policy.rbac.Action",
  "key": "something"
}

Configuring the Policy With a Policy Information Point

Plain RBAC can express “this user may obtain the scope something for this backend”. It cannot express “…​ but only when the exchange is an impersonation” or “…​ only when the subject token explicitly named this client in its may_act claim”. Everything beyond the resource and the action — who is exchanging, what was presented, in which mode, along which trust path — is token exchange context that the PDP does not see by itself.

Making that context available turns the token exchange context into a Policy Information Point: the policy refers to a token exchange attribute by its identifier, and the PDP looks its value up in the context of the request being evaluated. This requires three configuration steps.

1. Enable Resource Attribute Resolution in the PDP

Add the resource attribute finder module to the XACML PDP Service used by the token exchange PEP:

{
  "@odata.type": "#net.atos.dirx.access.apprepo.api.config.authz.pdp.XacmlPdpService",
  "key": "OAuth Token Exchange",
  "policyFinderModuleName": "com.siemens.dxa.services.authz.impl.xacml.pdp.finder.policy.policyservice.RbacPolicyFinderModule",
  "attributeFinderModuleNames": [
    "org.wso2.balana.finder.impl.CurrentEnvModule",
    "com.siemens.dxa.services.authz.impl.xacml.pdp.finder.attribute.subject.SubjectAttributeFinderModule",
    "com.siemens.dxa.services.authz.impl.xacml.pdp.finder.attribute.environment.EnvironmentAttributeFinderModule",
    "org.wso2.balana.finder.impl.SelectorModule",
    "com.siemens.dxa.services.authz.impl.xacml.pdp.finder.attribute.resource.ResourceAttributeFinderModule"
  ],
  "multipleDecisionProfile": true,
  "xacmlPolicyInterpretationTemplateId": {
    "key": "OAuth Token Exchange",
    "type": "net.atos.dirx.access.apprepo.api.config.authz.XacmlPolicyInterpretationTemplate"
  }
}

The multiple decision profile must remain enabled — the per-scope decisions are issued as a single multi-request.

2. Declare the Attributes to the Policy Interpretation Template

The XACML Policy Interpretation Template referenced by the PDP must list one XACML Attribute Template per token exchange attribute the policy wants to use. Every such attribute template points to a single XACML Attribute Value Template whose implementation is XACML_ATTRIBUTE_VALUE_BUILDER_TOKEN_EXCHANGE; that value template is what actually reads the token exchange context and it can be shared by all of them.

{
  "@odata.type": "#net.atos.dirx.access.apprepo.api.config.authz.XacmlAttributeValueTemplate",
  "key": "OAuth Token Exchange",
  "xacmlAttributeCategoryId": "Resource",
  "implClassName": "XACML_ATTRIBUTE_VALUE_BUILDER_TOKEN_EXCHANGE"
}
{
  "@odata.type": "#net.atos.dirx.access.apprepo.api.config.authz.XacmlAttributeTemplate",
  "key": "TE exchange-mode",
  "xacmlAttributeCategoryId": "urn:oasis:names:tc:xacml:3.0:attribute-category:resource",
  "attributeId": "solutions:dirx:access:oauth:token-exchange:exchange-mode",
  "dataType": "http://www.w3.org/2001/XMLSchema#string",
  "xacmlAttributeValueTemplateId": {
    "key": "OAuth Token Exchange",
    "type": "net.atos.dirx.access.apprepo.api.config.authz.XacmlAttributeValueTemplate"
  }
}

All token exchange attributes are resolved in the resource category, urn:oasis:names:tc:xacml:3.0:attribute-category:resource.

Available Token Exchange Attributes
Attribute identifier Cardinality Value

solutions:dirx:access:oauth:token-exchange:client-id

single

The client identifier of the client performing the exchange.

solutions:dirx:access:oauth:token-exchange:client-authenticated

single

true or false. Absent when the client authentication state is not known.

solutions:dirx:access:oauth:token-exchange:target-audience

single

The target audience currently under evaluation. This is the audience that also appears as the XACML resource-id.

solutions:dirx:access:oauth:token-exchange:resolved-target-audience

multiple

Every target audience resolved for the request, not only the one under evaluation.

solutions:dirx:access:oauth:token-exchange:requested-scope

multiple

All scopes requested by the request.

solutions:dirx:access:oauth:token-exchange:scope-ceiling

multiple

The upper bound the granted scopes must stay within. Absent when the evaluation is unconstrained.

solutions:dirx:access:oauth:token-exchange:exchange-mode

single

IMPERSONATION or DELEGATION.

solutions:dirx:access:oauth:token-exchange:downgrade-to-impersonation

single

true when a delegation request was downgraded to impersonation.

solutions:dirx:access:oauth:token-exchange:trust-path

single

SELF_AS when the subject token was issued by this OAuth Server, THIRD_PARTY when it came from a federation partner.

solutions:dirx:access:oauth:token-exchange:actor-trust-path

single

The same for the actor token.

solutions:dirx:access:oauth:token-exchange:subject-token-type

single

The subject token type URI.

solutions:dirx:access:oauth:token-exchange:actor-token-type

single

The actor token type URI.

solutions:dirx:access:oauth:token-exchange:requested-token-type

single

The requested token type URI.

solutions:dirx:access:oauth:token-exchange:subject-token:claim:<claim>

multiple

The value(s) of the named claim of the subject token.

solutions:dirx:access:oauth:token-exchange:actor-token:claim:<claim>

multiple

The value(s) of the named claim of the actor token.

Claim attributes address nested claims with dot-separated names, so the subject of a may_act claim is solutions:dirx:access:oauth:token-exchange:subject-token:claim:may_act.sub. The issuer of a token is reached as its iss claim.

Attributes that have no value in the current request are absent rather than empty. A reference to an absent attribute does not match, which means that policies fail closed — a rule requiring actor-token-type will simply not apply to a request that carries no actor token.

3. Use the Attributes in the Authorization Rule

Once the attributes are resolvable, an Authorization Rule can refer to them in two places. Which one to use depends on what the attribute is compared with:

  • Against a constant — in the target of the rule, through the All of element of a Resource.

  • Against another attribute — in a condition of the rule, through a String comparison condition.

Both can be combined in a single rule, and both are conjunctive: everything stated must hold for the rule to grant its actions.

Matching an Attribute Against a Constant

A Resource normally contributes a single match on the standard XACML urn:oasis:names:tc:xacml:1.0:resource:resource-id attribute, taken from its Path. Filling its All of element instead turns it into a composite resource whose target matches on several attributes at once.

Each All of entry is a pair:

  • an Attribute Id — the XACML attribute to match, which may be any of the token exchange attributes listed above, or urn:oasis:names:tc:xacml:1.0:resource:resource-id itself;

  • a list of Resource identifiers — the referenced Resources supply the constants to match against. Each referenced Resource contributes its Path as the value and its Comparison function as the matching function.

Because these are constants embedded in the policy target, the referenced Resources are ordinary Resource objects used purely as value holders: the Path carries the literal, not a URL.

The example below is a composite resource that matches only an exchange aimed at https://backend.acme.example/api and performed in impersonation mode:

{
  "@odata.type": "#net.atos.dirx.access.apprepo.api.config.policy.resource.Resource",
  "key": "TE Backend Acme",
  "pepId": { "key": "OAuth Token Exchange",
             "type": "net.atos.dirx.access.apprepo.api.config.client.OtherPep" },
  "allOf": [
    {
      "attributeId": "urn:oasis:names:tc:xacml:1.0:resource:resource-id",
      "resourceIds": [ { "key": "TE Backend Acme resource uri",
                         "type": "net.atos.dirx.access.apprepo.api.config.policy.resource.Resource" } ]
    },
    {
      "attributeId": "solutions:dirx:access:oauth:token-exchange:exchange-mode",
      "resourceIds": [ { "key": "TE exchange-mode equal IMPERSONATION",
                         "type": "net.atos.dirx.access.apprepo.api.config.policy.resource.Resource" } ]
    }
  ]
}

The two referenced Resources hold the constants. The first one is the target audience URI already used in the plain RBAC case; the second one holds the exchange mode literal and states the function it is matched with:

{
  "@odata.type": "#net.atos.dirx.access.apprepo.api.config.policy.resource.Resource",
  "key": "TE exchange-mode equal IMPERSONATION",
  "pepId": { "key": "OAuth Token Exchange",
             "type": "net.atos.dirx.access.apprepo.api.config.client.OtherPep" },
  "path": "IMPERSONATION",
  "comparisonFunction": "urn:oasis:names:tc:xacml:1.0:function:string-equal"
}

If Comparison function is not specified, the function is derived from the PEP: urn:oasis:names:tc:xacml:1.0:function:regexp-string-match when the related PEP has an authority assigned, and urn:oasis:names:tc:xacml:1.0:function:string-equal otherwise. State it explicitly for token exchange constants, where an exact match is almost always what is meant.

All entries of one All of, and all Resources referenced within them, must match together. Alternatives are expressed one level higher: the Resources listed on the Authorization Rule are alternatives to each other, so a rule that should apply to either of two backends references two composite resources rather than listing both in one.

Comparing Two Attributes

A constant cannot express a relation between two values of the same request. For that the rule carries a String comparison condition, configured with the Source category and Source attribute identifier, the Target category and Target attribute identifier, and the XACML Comparison function.

The target audience of the evaluation is present both as the token exchange attribute target-audience and as the standard resource-id. Tying them together guarantees that a rule written for one resource cannot be satisfied by an exchange aimed at another:

{
  "@odata.type": "#net.atos.dirx.access.apprepo.api.config.policy.rbac.condition.StringComparisonCondition",
  "key": "TE target-audience equal resource-id",
  "type": "STRING_COMPARISON",
  "sourceCategory": "urn:oasis:names:tc:xacml:3.0:attribute-category:resource",
  "sourceAttributeId": "solutions:dirx:access:oauth:token-exchange:target-audience",
  "targetCategory": "urn:oasis:names:tc:xacml:3.0:attribute-category:resource",
  "targetAttributeId": "urn:oasis:names:tc:xacml:1.0:resource:resource-id",
  "comparisonFunction": "urn:oasis:names:tc:xacml:1.0:function:string-equal"
}

The same mechanism enforces that the requesting client is the one the end user consented to, by comparing the may_act.sub claim of the subject token with the identifier of the requesting client. Neither value is known when the policy is written, so this cannot be expressed as a constant:

{
  "@odata.type": "#net.atos.dirx.access.apprepo.api.config.policy.rbac.condition.StringComparisonCondition",
  "key": "TE subject-token:claim:may_act.sub equal client-id",
  "type": "STRING_COMPARISON",
  "sourceCategory": "urn:oasis:names:tc:xacml:3.0:attribute-category:resource",
  "sourceAttributeId": "solutions:dirx:access:oauth:token-exchange:subject-token:claim:may_act.sub",
  "targetCategory": "urn:oasis:names:tc:xacml:3.0:attribute-category:resource",
  "targetAttributeId": "solutions:dirx:access:oauth:token-exchange:client-id",
  "comparisonFunction": "urn:oasis:names:tc:xacml:1.0:function:string-equal"
}
Putting It Together

The Authorization Rule below combines both mechanisms: its resource is the composite one that pins the audience and the exchange mode, its action is the scope, and its conditions relate the attributes that only the request itself can supply.

{
  "@odata.type": "#net.atos.dirx.access.apprepo.api.config.policy.rbac.AuthzRule",
  "key": "TE Backend Acme",
  "resourceIds": [ { "key": "TE Backend Acme",
                     "type": "net.atos.dirx.access.apprepo.api.config.policy.resource.Resource" } ],
  "actionIds": [ { "key": "something",
                   "type": "net.atos.dirx.access.apprepo.api.config.policy.rbac.Action" } ],
  "conditionIds": [
    { "key": "TE target-audience equal resource-id",
      "type": "net.atos.dirx.access.apprepo.api.config.policy.rbac.condition.StringComparisonCondition" },
    { "key": "TE subject-token:claim:may_act.sub equal client-id",
      "type": "net.atos.dirx.access.apprepo.api.config.policy.rbac.condition.StringComparisonCondition" }
  ]
}

Since each scope is a separate decision, rules can differentiate per scope: a rule granting a read scope may be plain RBAC while a rule granting a write scope pins the exchange mode in its target and requires a self-issued subject token and an authenticated client.

Claims of the Issued Token

Default Claims

The issued token carries the claims that the OAuth Server produces for any token of the requested type, plus the token-exchange-specific ones:

  • sub — the identifier of the subject resolved from the subject token.

  • act — the acting party, present in delegation mode. Nested exchanges nest the previous value as act.act, preserving the full delegation chain.

  • aud — the target audiences that survived the scope evaluation.

  • scope — the effective scopes, for access tokens.

  • client_id — the client that performed the exchange, for access tokens.

  • iat and exp — issuance and expiry, consistent with expires_in in the response.

  • auth_time — the authentication time, where an ID token is involved.

Injecting Additional Claims

Beyond the defaults, any claim of the subject token, the actor token, or the requesting client’s metadata can be copied into the issued token. This is what makes the exchanged token self-contained for the downstream service: the service receives the identity and context attributes it needs without having to call back to the authorization server or to a user directory.

Claim injection uses the regular attribute template mechanism. The exchange profile’s Attribute Template identifiers reference OAuth Attribute Templates. Each of these defines the Name under which the claim appears in the issued token, whether it is Mandatory, and the OAuth Attribute Value Template that produces its value.

For token exchange, the value template is configured with the source abstraction TOKEN_EXCHANGE and one of the following source abstraction details:

Source abstraction detail Value

SUBJECT_TOKEN

The claim of the subject token named by the Claim name element.

ACTOR_TOKEN

The claim of the actor token named by the Claim name element.

CLIENT

The metadata property of the requesting OAuth client named by the Claim name element, for example grant_types.

SUBJECT_RESOLUTION

The resolved subject identifier — the value that becomes the sub claim.

ACTOR_RESOLUTION

The resolved acting party — the value that becomes the act claim.

CURRENT_TIMESTAMP

The issuance time — the value that becomes the iat claim.

AUTH_TIME

The authentication time — the value that becomes the auth_time claim, where an ID token is involved.

The Claim name element applies only to SUBJECT_TOKEN, ACTOR_TOKEN and CLIENT; the remaining details identify their value on their own.

SUBJECT_RESOLUTION, ACTOR_RESOLUTION, CURRENT_TIMESTAMP and AUTH_TIME are imprinted into the issued token by default and do not need to be configured. They are exposed as source abstraction details so that they can be additionally published under a different claim name, or post-processed — for example through the Return type, or through the regular expression and template elements of the value template — when a downstream service expects a different representation.

The Return type of the value template determines how the resolved value is rendered into the token: as a string, a number, a boolean, a list, or the untouched original structure. Copying a structured claim, such as a JSON object, requires a return type that preserves it.

Security Considerations

Token exchange issues credentials on the strength of other credentials, so the trust it establishes is transitive. The following points deserve attention when designing a deployment.

Restrict the profile, but do not rely on routing alone

Determining parameters are evaluated before anything else and reject an unwanted caller, source token issuer or requested token type at the cheapest possible point. They act on the request as stated, however, so they narrow which rules apply rather than proving anything about the caller. Pair every routing restriction that matters for security with an equivalent condition in the scope evaluation policy, which runs after the client and the presented tokens have been verified.

Be deliberate about public clients

Enabling Do public client support for token endpoint on an exchange profile admits clients that present no client_secret, so the client_id in the request is an unverified assertion. Such a profile should not grant scopes on the strength of the client’s identity; use the client-authenticated attribute in the policy to keep sensitive scopes reserved for confidential clients.

Do not leave the scope gate open

An exchange profile without a Token Exchange PEP grants every requested scope. This is convenient during integration but should not survive into production, since it lets any client that matches the profile mint a token for any scope the target service recognizes.

Prefer delegation to impersonation

A delegated token records the acting party and lets the downstream service and the audit trail distinguish “the user did this” from “a service did this on the user’s behalf”. Impersonation discards that information irreversibly.

Let the subject’s token authorize the actor

The may_act requirement moves the decision about who may act for a user from the client’s request into the token the user’s own authentication produced. Combined with a policy condition comparing may_act.sub with the requesting client, it prevents a compromised client from acting for arbitrary users.

Bound the lifetime

Enable Cap to source wherever an exchange chain is possible, and set Maximum lifetime to the shortest value the downstream service can work with. Without these, every exchange resets the expiry and a chain of exchanges extends the reach of the original credential indefinitely.

Treat third-party tokens differently

The trust path attribute distinguishes tokens minted by this OAuth Server from tokens accepted from a federation partner. Only tokens on the first path have their revocation state checked and yield a live session subject; a policy that grants sensitive scopes should therefore normally require SELF_AS, or at least demand additional conditions when the subject token came from outside.

Keep the list of trusted external issuers minimal

Every entry in Trusted issuers for external audience is a party whose signature alone is enough to have a token exchanged, without this OAuth Server being able to see whether that token is still valid at its issuer. List only issuers that genuinely need this, and rely on the token exchange attributes rather than role assignments to bound what their tokens can obtain.

Keep audience names meaningful

The target audience URI is simultaneously the aud claim of the issued token and the resource identifier of the authorization decision. Reusing one URI for several services means a token authorized for one of them is accepted by all.

Error Responses

Error Typical causes

invalid_request

subject_token or subject_token_type missing; a token type URI the server does not know (Unsupported subject_token_type. and analogously for the other two parameters); a token type triple outside the supported combinations (Invalid combination of token types., see Supported Token Type Combinations); actor_token present without actor_token_type or vice versa; a presented token that is not a valid JWT or carries no iss claim; a presented token that has expired or is not yet valid; a resource value containing a fragment; a required may_act claim absent or naming a different actor.

invalid_grant

A self-issued presented token that has been revoked or is unknown; a signature that cannot be verified; an external issuer that is not listed in Trusted issuers for external audience or provides no key set; a subject that cannot be resolved because the applicable authentication method is not configured. See Subject and Actor Resolution.

invalid_target

No exchange profile matches the request (No matching exchange profile.); an audience value cannot be resolved; a resource URI is unknown; the target is not a trusted peer; no audience survives the scope evaluation (No valid target audience after scope evaluation).

invalid_scope

The scope evaluation could not be carried out; the effective scope is empty under EMPTY_TO_ERROR; not all requested scopes were granted under EXACT; the audiences do not yield a uniform scope under REQUIRE_UNIFORM.