OAuth 2.x and OpenID Connect sequence diagrams
Published:
Updated:
Some sequence diagrams about OAuth 2.x and OpenID Connect.
Some sequence diagrams of OAuth 2.X and OpenID Connect. They provide an overview/summary/roadmap of several OAuth and OpenID Connect (OIDC) specifications. Look at the specifications and other references for details.
Table of content
OAuth
Grant (Flow) | Initial Request |
---|---|
Authorization Code Grant | frontchannel GET/POST authorization_endpoint (response_type=code) |
Implicit Grant | frontchannel GET/POST authorization_endpoint (response_type=token) |
Device Authorization Grant | backchannel POST device_authorization_endpoint |
Client Credential Grant | backchannel POST token_endpoint (grant_type=client_credentials) |
Resource Owner Password Credentials Grant | backchannel POST token_endpoint (grant_type=password) |
Assertion Grants | backchannel POST token_endpoint (grant_type=some assertion type) |
Token Exchange | backchannel POST token_endpoint (grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchangehttp://127.0.0.1:4567/) |
Main flows
Authorization Code Grant
This is grant is used to let a client application (such as a web application) obtain an authorization (in the form of an access token) on behalf of a user (resource owner). The client application redirects the user to the authorization server frontend (usually in a web application) where the user can authenticate itself and consent to provide the authorization to the client application.
Warning: user-agent for authorization server frontend code
Native client applications, should use an external user-agent for the authorization server frontend code i.e. either a standalone browser or an in-app browser tab. (such as Android Custom Tab, iOS ASWebAuthenticationSession or cordova-plugin-browsertab).
It should not use an embedded / in-app browser to execute the authorization server frontend logic (WebView, Cordova InAppBrowser).
In-app browser executes the authorization server frontend code in the system/user browser while the in-app browser tab executes the authorization server frontend code in the client application. In the first case, the user credentials are isolated from the client application.
Some extensions (which are represented in the diagram):
- Proof Key for Code Exchange (PKCE);
- Authorization Server Issuer Identification;
- Resource Indicators for OAuth 2.0;
- Rich Authorization Requests.
Client Credentials Grant
The Client Credentials Grant is used by the client application in order to obtain an access token on its own behalf (not on behalf of a user).
Device Authorization Grant
The Device Authorization Grant is used for provisioning an access token (on a user's behalf) to devices which cannot execute a browser or have limited interactivity.
Token Usage
Bearer Access Token Usage
Refreshing a Token
Refresh tokens are used by the client to obtain fresh access tokens from the authorization server. The idea is to have short-lived (possibly stateless) access token while still allowing for revocation of the authorization. Moreover by forcing the client to make periodical refresh request to the authorization server, the authorization can detect whether a grant is no longer used and revoke it.
Token Revocation
Token Revocation is used by the client application to revoke a token (either a refresh or an access token).
Token Introspection
Token Introspection is used by the resource server to get information about an (access) token (including whether it is still valid).
Note: Token introspection on refresh token
The specification allows to use token introspection on the refresh token as well. However, I feel that this is ill defined as the refresh token is expected to be consumed by the authorization server itself.
Note: Token type hint
Moreover the token_type_hint
is supposed to be only an hint (and the actual type is not returned by the API). I think this behavior might lead to token confusions vulnerabilities.
OAuth configuration
OAuth Server Metadata
Server Medata is exposed by the Authorization Server to advertize its configuration, its endpoints, etc. See the references for links to real examples of server metadata documents.
OAuth Client Registration
Client registration may be used by the client application for registering itself on the authorization server (and avoiding manual configuration) and for updating its registration.
Authorization request protection
The following approaches may be used (or combined) to protect the privacy and/or integrity of the authorization request.
JWT-Secured Authorization Request
With JWT-Secured Authorization Request (JAR), the authorization request is a JWT which can be signed or signed-then-encrypted.
Pushed Authorization Requests
With Pushed Authorization Requests (PAR), the client application sends the authorization request directly to the authorization server (backchannel communication) instead of sending it through the user agent (frontchannel communication). This prevents the user from having access to the authorization request and from tampering with it.
Bound Tokens
Certificate-Bound Access Tokens
Certificate-Bound Access Tokens are access tokens which can only be used on top of a mTLS connection associated with a given client certificate. This protects against access token leakage. In particular, this makes it possible for the authorization server to safely issue a single access token which can be consumed by several (unrelated, untrusting) resource servers[1].
Demonstrating Proof-of-Possession
Demonstrating Proof-of-Possession (DPoP) is an alternative to Certificate-bound Access Tokens when mTLS is not practical (eg. for Single Page Applications). The idea is the same but demonstration of the possession of a private key is given at the application (HTTP) layer (in a DPoP
HTTP header) instead of the TLS layer.
Advanced Grants
These mechanisms are used for plumbing such as interworking with other authorization/authentication systems.
Assertion Grants
Token Exchange
Token Exchange may be used:
- to exchange a token to/from a foreign system (eg. to/from SAML);
- by a resource server to exchange a user access token into a new access token for accessing another resource server on behalf of the user (delegation or impersonation);
- to obtain of token with modified scope.
This is a very general framework for exchanging tokens. A lot here is left to interpretation/profiling.
Value | Semantic |
---|---|
urn:ietf:params:oauth:token-type:access_token | (Opaque) Access Token issued by the AS |
urn:ietf:params:oauth:token-type:refresh_token | (Opaque) Refresh Token issued by the AS |
urn:ietf:params:oauth:token-type:id_token | OpenID Connect ID Token |
urn:ietf:params:oauth:token-type:saml1 | SAML1 token (encoded in base64url) |
urn:ietf:params:oauth:token-type:saml2 | SAML2 token (encoded in base64url) |
urn:ietf:params:oauth:token-type:jwt | JWT |
Some references:
- OAuth2 Token Exchange in Practice by Sagara Gunathunga
- How token exchange works (Keycloak)
Legacy OAuth Grants
These two grants can be considered as deprecated and is not going to specified in OAuth 2.1.
Implicit Grant
The implicit grant was intended to be used for non-confidential clients. You should not use the authorization code grant with Proof Key for Code Exchange (PKCE) which is more secure.
Note: lack of support for refresh tokens for some grants
Refresh tokens are NOT supported for the implicit[2] grant and for the client credentials grant.
Resource Owner Password Credentials Grant
In this insecure legacy flow, the user provides his/her password directly to the client application.
Note: limitations of the resource owner password grant
The password grant is very insecure and limited:
- The user password is given to the OAuth client (which could use it for whatever). This kind of defeats the purpose of OAuth which is to avoid giving your credentials to the client application in the first place.
- It only support password-based authentication (no MFA, WebAuthn, passkeys, etc.).
- There is no provision for for checking the user consent and the user cannot check which authorizations are being requested.
OAuth Discovery (drafts)
OAuth Authorization Server Discovery
Authorization Server Discovery (draft) let the client application discover the authorization server to be used for a resource server.
Warning: Access Token exfiltration
Using this mechanism, a malicious server could pretend to be a resource server for https://as
. A client could initiate an OAuth flow with the authorizaton server, obtain an access token to the malicious server. This malicious server could then use this access token. I therefore think that additional mechanisms are needed to make this work safely.
OAuth Client Discovery
Client Discovery (draft) let the authorization server discover the client instead of having the the client register itself.
OpenID Connect
Flow | response_type | nonce | c_hash | at_hash | …:rt_hash |
---|---|---|---|---|---|
Authorization code flow | code | OPTIONAL | OPTIONAL | OPTIONAL | N/A |
Implicit flow | id_token token | REQUIRED | OPTIONAL | REQUIRED | N/A |
id_token | REQUIRED | OPTIONAL | OPTIONAL | N/A | |
Hybrid flow | code id_token | REQUIRED | REQUIRED[3] | REQUIRED[3:1] | N/A |
code token | REQUIRED | OPTIONAL | OPTIONAL | N/A | |
code id_token token | REQUIRED | REQUIRED[3:2] | REQUIRED[3:3] | N/A | |
CIBA push mode | N/A | N/A | N/A | REQUIRED | REQUIRED[4] |
CIBA other modes | N/A | N/A | N/A | OPTIONAL | OPTIONAL |
Authorization Code Flow
See Initiating User Registration via OpenID Connect 1.0 for prompt=create
which let the Relying Party request a user creation flow.
Token Usage
User Information
In OpenID Connect, the access token can be used to obtain information about the authenticated user using the userinfo_endpoint
.
Refreshing a Token
In a refresh token response, an id_token
may be returned by the OpenID Provider but this is not required.
Other OpenID Connect Flows
Implicit flow
Hybrid flow
Note: at_hash
and c_hash
claims
The at_hash
and c_hash
claims contain half of the hash of the access_token
and code
respectively. The former is required in both implicit and hybrid flows. The latter is required in the ID token returned by the authorization endpoint in the hybrid flow. They protect against access token and authorization code substitution attacks respectively.
OpenID Connect Discovery and Registration
OIDC Discovery is based on Webfinger.
Third-party Inititated Login
In Third-party Inititated Login, the login process is initiated by the OpenID provider or another party.
Session Management
The Session Managerment feature uses a <iframe>
for front-channel communication of session state update. The Relying Party includes a iframe
of the OpenID Provider. This iframe
sends message to its parent (the Relying Party) when it want to signal changes of the session.
Note: two iframes
The specification mentions two iframe
s. But as far as I understand, the Relying party iframe
is not stricly absolutely necessary and is only an implementation detail.
Logout
Front-channel logout
With front-channel logout, the logout process is initiated by the OpenID Provider through the user UA (front-channel request) using a <iframe>
.
Back-channel logout
With back-channel logout, the logout process is initiated by the OpenID Provider using a direct (back-channel) request.
Relying-Party initiated logout
CIBA
Note: CIBA without OpenID Connect
You might want to use CIBA in plain OAuth 2 (without OpenID Connect). However, the specification is defined in the context of OpenID Connect and its usage without OpenID Connect it unspecified.
Appendix, Token Summary
Name | Flow | Content |
---|---|---|
Authorization code (code ) | AS → client → AS | opaque |
Access Token (access_token ) | AS → client → RS | opaque to clients (may be a JWT, at+jwt ) |
Refresh token (refresh_token ) | AS → client → AS | opaque (sometimes a JWT) |
JWT-Secured Authz. Request (JAR) (request ) | client → AS | JWT (oauth-authz-req+jwt ) |
JWT-Secured Authz. Response Mode (JARM) | AS → client | JWT |
JWT response for Token Introspection | AS → RS | JWT (token-introspection+jwt ) |
DPoP Proof-of-possession (DPoP HTTP header) | client → AS / RS | JWT (dpop+jwt ) |
Software Statement (software_statement ) | client vendor → client → AS | JWT |
Authorization state (state ) | client → AS → client | opaque |
Logout state (state ) | client → AS → client | opaque |
DPOP Nonce | AS → client → AS | opaque |
RS → client → RS | opaque | |
PKCE Code Verifier (code_verifier ) | client → AS | opaque (random) |
PKCE Code Challenge (code_challenge ) | client → AS | hash of the code verifier (base64url) |
OIDC ID token (id_token ) | OP (AS) → client | JWT |
OIDC Nonce (nonce ) | client → AS → client | opaque |
OIDC Session ID (sid ) | AS → client → AS | opaque |
OIDC Session State (session_state ) | OP (AS) → client | opaque |
OIDC private_key_jwt and client_secret_jwt client authentication (client_assertion ) | client → OP / AS | JWT |
Appendix, Client Authentication Methods
Possible client authentication methods (*_auth_methods_supported
, etc.) include:
none
;client_secret_basic
, HTTP Basic Authentication (client_id
+client_secret
);client_secret_post
, in the HTTP Post Body (client_id=...&client_secret=...
);client_secret_jwt
, JWT protected (MAC) with theclient_secret
(client_assertion=...&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
)private_key_jwt
, JWT protected (signed) with some client keypair (same parameters as above);tls_client_auth
, mTLS (using a PKI);self_signed_tls_client_auth
, mTLS with a (self-signed) certificate registered by the client throughjwks
orjwks_uri
.
In addition, client assertions can be used for client authentication (client_assertion=...&client_assertion_type=...
):
urn:ietf:params:oauth:client-assertion-type:jwt-bearer
urn:ietf:params:oauth:client-assertion-type:saml2-bearer
(encoded in base64url)
Appendix, Testing OpenID Connect using Keycloak
Keycloak is an Apache-licensed Identity and Access Management (IAM) software. We can quickly spawn a local instance in a container in order to experiment with OAuth and OpenID Connect:
podman run --name keycloak -p 127.0.0.1:8080:8080\
-e KEYCLOAK_ADMIN=admin \
-e KEYCLOAK_ADMIN_PASSWORD=change_me \
quay.io/keycloak/keycloak:20.0.1 start-dev
A different port can be used:
podman run --name keycloak -p 127.0.0.1:3000:3000 \
-e KEYCLOAK_ADMIN=admin \
-e KEYCLOAK_ADMIN_PASSWORD=change_me \
quay.io/keycloak/keycloak:20.0.1 start-dev --hostname-port=3000 --http-port=3000
Some interesting Docker/Podman arguments:
-v keycloak:/opt/keycloak/data
Some interesting KeyCloak arguments:
--features=declarative-user-profile,par,token-exchange,ciba,impersonation,step-up-authentication
, add features
Interesting endpoints:
/admin/
, administration user interface (create new users, realms, configure client applications);/realms/master/account
, user interface to login to themaster
realm;/realms/master/.well-known/openid-configuration
, metadata for themaster
realm.
The Keycloak web site hosts a simple test OpenID connect client which can be used to test the OIDC provider.
See as well:
- Keycloak Guides
- Running Keycloak in a container
- Securing Applications and Services Guide
- Awesome Keycloak, “carefully curated list of awesome Keycloak resources”
References
Relevant IANA registries:
- OAuth Parameters (IANA registry)
- Authentication Method Reference Values (IANA registry)
- JWT registry
Lists of specifications:
- OAuth 2.x specifications
- OAuth at IETF Data Tracker
- OpenID specifications
- OpenID specifications and drafts (raw directory listing)
- OAuth & OpenID Link List, a list of selected specifications in the OAuth & OpenID spaces and where to find them
UMA 2.0:
- User-Managed Access (UMA) 2.0 Grant for OAuth 2.0 Authorization
- Federated Authorization for User-Managed Access (UMA) 2.0
Informational:
- OAuth 2 Simplified
- OAuth client authentication - more than just client secrets
- List of public OpenID Connect providers
- PKCE vs. Nonce: Equivalent or Not?
- OAuth from First Principles
Related:
- RFC 9200, ACE-OAuth (i.e. OAuth adapted for IoT, based on CoAP insteaf of HTTP, CBOR instead of JSON and COSE instead of JWT)
Examples of Server Metadata:
- Pro Santé Connect, based on KeyCloak
- Pro Santé Connect (sandbox), based on KeyCloak
- France connect (integration) (see the documentation)
- France identité
- Agent Connect (see the documentation)
- Agent Connect (integration)
- Mobile Connect, based on KeyCloak
- Yris, based on KeyCloak
- Microsoft ADFS, where
microsoft.com
is the tenant ID for Microsoft itself - Microsoft online
- AppleID
- Yahoo
- Slack
- SwissID (see the documentation)
- PayPal
- Crédit Agricole
- Login.gov, SSO for connecting to US agencies (see the OIDC documentation and the list of user attributes)
- Login.gov integration
- Tesla
- Royal Bank of Scotlang sandbox (OpenBanking)
- HSBC (OpenBanking)
- Tesco Bank (OpenBanking)
- 1password on Okta
- Self Issued OpenID (see spec)
- France Travail candidats and entreprises (see documentation)
- Lifen, see documentation
- GitHub Actions
- GitLab
- Amazon
Microsoft Active Directory Federation Service (ADFS):
- MS-OAPX, OAuth 2.0 Protocol Extensions
- MS-OAPXBC, OAuth 2.0 Protocol Extensions for Broker Clients
- AD FS OpenID Connect/OAuth concepts
- AD FS OpenID Connect/OAuth flows and Application Scenarios
- OpenID Connect on the Microsoft identity platform
- Microsoft identity platform and OAuth 2.0 On-Behalf-Of flow
Keycloak:
Integration with SCIM:
- SCIM for JIT Provisioning (expired draft) ~ Relationship to OpenID Connect, suggests mapping the SCIM "username" attribute with the OIDC "sub" claim.
- OpenID Connect Profile for SCIM Services suggests adding a "scim_id" ID token claim indicating the SCIM user "id" attribute
Documentation of some existing implementations and services:
- KeyCloak, Securing Applications and Services Guide
Security:
HEART Working Groupe (health-related):
- HEART for OAuth 2.0
- HEART forFHIR) OAuth 2.0 Scopes
- HEART for OpenID Connect 1.0
- HEART for UMA 2.0
- HEART for FHIR UMA 2 Resources
- Patient-Centric Data Sharing with UMA
Other:
Without this, RS1 (resource server 1) could receive an access tokens with
"aud":["rs1","rs2"]
from the client and use it on RS2. ↩︎See “Why in implicit grant grant , the auth server MUST NOT issue a refresh token” for why the refresh token is not supported in the implicit grant. ↩︎
The
c_hash
andat_hash
claims are REQUIRED in theid_token
returned as part of the authentication response (when the corresponding value is present as well). They are OPTIONAL (when relevant) in theid_token
returned in the Access Token Response. ↩︎ ↩︎ ↩︎ ↩︎If a
refresh_token
is sent. ↩︎