More grants and connected applications
More ways for a client to get an access token, and how people and administrators see and end what applications were given.
Turn each grant on in Flow Policy and select it on each client that needs it.
Device authorization
A TV, a console or a command line tool cannot easily open a sign-in page, so it asks for a code instead (RFC 8628):
POST /oauth/device_authorization
Content-Type: application/x-www-form-urlencoded
client_id=<client ID>&scope=openid offline_accessThe answer holds a device_code the device keeps, and a user_code such as WDJB-MJHT with the address /oauth/device to show the person. The person opens it on a phone or computer, signs in to this tenant, enters the code and sees which application asks for what. Allowing or denying is recorded in protocol Audit. A confidential client authenticates with its registered method; a public client sends only its client_id. Flow Policy sets how long a device code lasts (300 to 1800 seconds, 600 by default).
Polling
Meanwhile the device asks the token endpoint with grant_type=urn:ietf:params:oauth:grant-type:device_code and its device_code. Until the person decides it gets authorization_pending; a device that asks again sooner than the interval (5 to 60 seconds, set in Flow Policy) gets slow_down and must wait 5 seconds longer from then on. A denied code gets access_denied, an old one expired_token, and an approved one its tokens, once: an ID token with openid, and a refresh token with offline_access.
JWT bearer assertions
With the JWT bearer assertion grant (RFC 7523), a client presents a JWT that another identity provider signed about a person, and receives an access token for the matching user of this tenant:
POST /oauth/token
Authorization: Basic <client credentials>
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=<JWT>&scope=photos.readThe JWT must come from a trusted issuer that allows this client, be signed with one of its keys (ES256, PS256, RS256 or EdDSA (Ed25519)), name this tenant's issuer or token endpoint in aud, carry a sub even when people are matched by another claim, and expire within the issuer's longest lifetime. One with a jti works once. Its header typ must be absent, JWT, or oauth-id-jag+jwt from the Identity Assertion Authorization Grant draft: a JWT typed for another purpose, above all an access token (at+jwt), is refused whoever signed it (assertion_type_refused), so an identity provider's access token can never be replayed here as a grant. An assertion that names a client_id, as an identity assertion must, works only for that client (assertion_client_mismatch). No one signs in here, so openid is refused and no refresh token is issued. Refusals answer invalid_grant, and protocol Audit records why, such as untrusted_issuer, subject_not_found or assertion_expired.
Trusted issuers
Add issuers under Trusted issuers on the Flow Policy page. Each has its iss value, its keys (a JWKS pasted in, or a jwks_uri fetched under the same outbound policy as client keys; another tenant of this environment, such as a second lab tenant, may be used), the claim that names the person (sub, or email, which then must arrive with email_verified: true), how that claim finds a user here (external ID by default, user name or email address), the clients that may use it, and the longest assertion lifetime (60 to 3600 seconds). Matching by email trusts the issuer to have verified the address, and an address can move between people, so prefer the external ID your provisioning sets. A tenant cannot trust itself.
Token exchange
A service that received a user's access token can trade it for one aimed at another API (RFC 8693), with grant_type=urn:ietf:params:oauth:grant-type:token-exchange, the user's token as subject_token and subject_token_type=urn:ietf:params:oauth:token-type:access_token, and the target API as resource or audience. The new token is for the same user, with the same or fewer scopes and the original sign-in's auth_time, amr and acr; it has no refresh token. Each client chooses how in its settings:
- Delegation, the default: the client must also send an
actor_tokenissued to itself, such as its own client credentials token, and the new token names it inact, keeping any earlier chain inside. - Impersonation: no actor token, and the new token stands for the user alone, so the API cannot tell a service is acting. Choose it only when a service must look exactly like the user.
To decide who may act for a client's users, enter a client ID in that client's Client that may act for this client's users setting. Access tokens the client then receives for a user carry may_act with that client_id (RFC 8693 section 4.4), and token exchange accepts them only from that client, in either mode; any other client is refused with invalid_request (actor_not_permitted). may_act names one party, so one client can be chosen. Saving a change ends the tokens the client already holds, like other changes to what a client may do, and the change is recorded in Audit. Leave it empty to let any client that token exchange allows trade the tokens. Claim mappings and scripts cannot set may_act; only this setting does, and a client's own registration update keeps it.
A client can map a scope from the token it exchanges to another scope for one resource, such as photos.read to storage.read for a storage API, under Token exchange scope mappings in its settings: one mapping per line, up to 20, written as the held scope, the scope to issue and the resource's identifier. The scope to issue must be one the client can be granted and must not belong to another resource, neither scope may be openid or offline_access (an exchanged token never carries them, so it cannot read UserInfo or be refreshed), and the resource must be among the client's Allowed resources when it lists any. When the client exchanges a token for one addressed to that resource, the held scope becomes the mapped scope, or the client can ask for the mapped scope by name. Without a mapping, an exchanged token can only keep or drop the scopes the traded token holds. Saving a mapping keeps the client's tokens working, is recorded in Audit, and a mapped scope cannot be deleted until no mapping names it. Protocol Audit records an exchange that used a mapping as exchange_scope_mapped, a mapped scope asked for another resource as scope_mapping_resource_mismatch, and a scope no mapping or rule reaches as scope_not_granted.
Protocol Audit for each exchange of a user token also lists the jti of the subject token, of the actor token and of the issued token, once each is known, and the scopes that were mapped, so an exchange can be traced to the tokens involved. A workload exchange of an externally signed JWT records no jti values. The tokens themselves are never recorded.
Only tokens this tenant issued for a user can be exchanged, and only by the client they were issued to or by a client linked to their API as a resource server under Resources, so a client cannot trade a token meant for someone else. The new token never outlives the token it came from, and it ends with it: revoking the original token, through /oauth/revoke, a disconnected application, a replayed code or refresh token or any other revocation, also revokes every token traded from it, however many times it was traded again. The Audit record of a revocation through /oauth/revoke, an administrator disconnecting an application, or a replayed code or refresh token says how many exchanged tokens it also revoked. A chain of exchanges is bounded: a token that already comes from 8 earlier exchanges cannot be exchanged again, and is refused with invalid_request (exchange_chain_too_long); exchange a token closer to the original instead. This is a fixed protocol bound on one token's chain, which keeps each token's record of where it came from small, not a usage limit on anyone's activity, so it does not appear in usage views. A token traded for one bound to a client certificate is bound to the same certificate, so the exchange must arrive over mutual TLS with it. A subject or actor token that cannot be used is refused with invalid_request, and protocol Audit names the reason, such as subject_token_not_for_client, actor_token_required or subject_token_invalid.
Connected applications
Each person's Security page lists the applications they allowed or that hold their tokens, with what each may use and when it last received a token, and Disconnect ends that application's access at once: remembered consent is removed and its tokens and pending codes revoked. Administrators with the grant permissions see the same list under View/edit details (View details without permission to edit the user) in User Management and can disconnect for the user. An API that validates JWT access tokens itself, without introspection, can keep accepting one until it expires. In Flow Policy, Who may approve applications can limit people to applications an administrator approved in their client settings; others are refused with access_denied (client_not_approved) on the consent page and on the device page, including for people who allowed them before, and their refresh tokens stop working until an administrator approves the application. Access tokens already issued keep working until they expire. Clients set to skip consent need no approval, and the JWT bearer and token exchange grants, where no one allows the application, are governed by each trusted issuer's allowed clients and by linked resources instead. Turning a client off blocks it for everyone.
Permissions, history and limits
Reading and changing trusted issuers need their own tenant permissions, which Tenant Admin holds, and every change is recorded in Audit. Reading and disconnecting a user's applications need tenant.grants.read and tenant.grants.revoke; each read and disconnection is recorded with the user as subject. A tenant can keep 20 trusted issuers and 500 device codes waiting for approval, and each person can enter 10 codes in 15 minutes; these appear in the tenant's usage view.