OpenID Connect · OAuth 2.0

The flows in diagrams

Who talks to whom, in what order. Solid lines are requests, dotted lines are responses. To choose, start with Which flow should I choose?

Authorization Code + PKCE · Hybrid (code id_token, code token…) · Implicit (id_token, id_token token) · Refresh Token · Client Credentials · Password (ROPC) · Device Code (RFC 8628) · Token exchange (RFC 8693) · Logout (RP-initiated and back-channel) · Introspection and revocation · private_key_jwt and JWT Bearer (RFC 7523) · PAR and JAR (RFC 9126 and 9101) · JARM (signed authorization response) · DPoP (RFC 9449) · CIBA (Client-Initiated Backchannel)

Authorization Code + PKCE Recommended

The standard flow: the browser only sees a single-use code, tokens go from server to server.

BrowserApplicationProvider (OP)API1. Generates code_verifier,state, nonce2. 302 to /authorize(challenge, state, nonce)3. GET /authorize4. Sign-in and consent page5. Credentials and consent of the person6. 302 redirect_uri?code=…&state=…7. GET /callback?code=…&state=…8. POST /token (code,code_verifier, secret)9. ID token + access token (+refresh token)10. Verifies signature, iss,aud, nonce11. Authorization: Bearer access_token12. Requested data
Text version of the diagram
  1. Application: Generates code_verifier, state, nonce
  2. Application → Browser : 302 to /authorize (challenge, state, nonce)
  3. Browser → Provider (OP) : GET /authorize
  4. Provider (OP) → Browser: Sign-in and consent page
  5. Browser → Provider (OP): Credentials and consent of the person
  6. Provider (OP) → Browser : 302 redirect_uri?code=…&state=…
  7. Browser → Application : GET /callback?code=…&state=…
  8. Application → Provider (OP) : POST /token (code, code_verifier, secret)
  9. Provider (OP) → Application : ID token + access token (+ refresh token)
  10. Application: Verifies signature, iss, aud, nonce
  11. Application → API : Authorization: Bearer access_token
  12. API → Application: Requested data

Use when: Any website, mobile app, SPA or desktop application where a person signs in.

What sets it apart: This is the foundation. All the other flows are a variant or special case of it.

ID-Kit can play it: test provider (your application against ID-Kit) and test application (your provider against ID-Kit).

Hybrid (code id_token, code token…) Specific cases

The identity is received immediately in the browser, and the code to obtain the tokens safely.

BrowserApplicationProvider (OP)1. 302 to /authorize(response_type=code id_token)2. GET /authorize then sign-in3. 302 redirect_uri#code=…&id_token=…&state=…4. A script reads the fragmentand sends it back5. POST /callback (code,id_token, state)6. Verifies id_token and c_hash7. POST /token (code,code_verifier)8. access token (+ refreshtoken)
Text version of the diagram
  1. Application → Browser : 302 to /authorize (response_type=code id_token)
  2. Browser → Provider (OP) : GET /authorize then sign-in
  3. Provider (OP) → Browser : 302 redirect_uri#code=…&id_token=…&state=…
  4. Browser: A script reads the fragment and sends it back
  5. Browser → Application : POST /callback (code, id_token, state)
  6. Application: Verifies id_token and c_hash
  7. Application → Provider (OP) : POST /token (code, code_verifier)
  8. Provider (OP) → Application : access token (+ refresh token)

Use when: An application that must know the person before exchanging the code (server-side session validation, old libraries).

What sets it apart: Like the code flow, but the ID token arrives right in the redirect (with c_hash binding it to the code).

ID-Kit can play it: test provider (your application against ID-Kit) and test application (your provider against ID-Kit).

Implicit (id_token, id_token token) Discouraged

Tokens arrive directly in the address: simpler, but exposed.

Browser (SPA)Provider (OP)API1. Generates state and nonce2. GET /authorize(response_type=id_token token)3. 302redirect_uri#id_token=…&access_token=…4. Reads the fragment, verifies thetoken5. Authorization: Bearer access_token
Text version of the diagram
  1. Browser (SPA): Generates state and nonce
  2. Browser (SPA) → Provider (OP) : GET /authorize (response_type=id_token token)
  3. Provider (OP) → Browser (SPA) : 302 redirect_uri#id_token=…&access_token=…
  4. Browser (SPA): Reads the fragment, verifies the token
  5. Browser (SPA) → API : Authorization: Bearer access_token

Use when: Almost never. Only for old SPAs or to check that an application properly forbids it.

What sets it apart: No code exchange: no back channel, no refresh token, tokens visible in the browser history.

ID-Kit can play it: test provider (your application against ID-Kit) and test application (your provider against ID-Kit).

Refresh Token Complement

Renew a short-lived access token without asking the person again.

ApplicationProvider (OP)API1. Authorization: Bearer access_token2. 401 invalid_token (expired)3. POST /token(grant_type=refresh_token)4. Revokes the old refreshtoken (rotation)5. New access token + newrefresh token6. Authorization: Bearer new access_tokenIf the old refresh token isreplayed, the whole token familyis revoked.
Text version of the diagram
  1. Application → API : Authorization: Bearer access_token
  2. API → Application: 401 invalid_token (expired)
  3. Application → Provider (OP) : POST /token (grant_type=refresh_token)
  4. Provider (OP): Revokes the old refresh token (rotation)
  5. Provider (OP) → Application : New access token + new refresh token
  6. Application → API : Authorization: Bearer new access_token

Use when: As soon as you want short access tokens while keeping the person signed in for a long time (offline_access scope).

What sets it apart: This is not a sign-in flow: it extends a session obtained with another flow.

ID-Kit can play it: test provider (your application against ID-Kit) and test application (your provider against ID-Kit).

Client Credentials Machine to machine

No person: the service authenticates with its secret.

ServiceProvider (OP)API1. POST /token(grant_type=client_credentials,scope)2. Verifies the client secret3. access token4. Authorization: Bearer access_token5. Data
Text version of the diagram
  1. Service → Provider (OP) : POST /token (grant_type=client_credentials, scope)
  2. Provider (OP): Verifies the client secret
  3. Provider (OP) → Service : access token
  4. Service → API : Authorization: Bearer access_token
  5. API → Service: Data

Use when: A service, a scheduled task or a daemon calling an API in its own name.

What sets it apart: No browser, no ID token, no refresh token: only an access token limited to the client's scopes.

ID-Kit can play it: test provider (your application against ID-Kit) and test application (your provider against ID-Kit).

Password (ROPC) Avoid

The application collects the password itself and sends it to the provider.

PersonApplicationProvider (OP)1. Enters username andpass2. POST /token(grant_type=password, username,password)3. access token (+ refreshtoken) or error
Text version of the diagram
  1. Person → Application: Enters username and password
  2. Application → Provider (OP) : POST /token (grant_type=password, username, password)
  3. Provider (OP) → Application: access token (+ refresh token) or error

Use when: Avoid. Only for migrating from an old system or for automated tests.

What sets it apart: Bypasses the provider's page: no MFA, no SSO, easier phishing.

ID-Kit can play it: test provider (your application against ID-Kit) and test application (your provider against ID-Kit).

Device Code (RFC 8628) Devices without a browser

The device displays a short code; the person validates it on their phone.

DeviceProvider (OP)Phone / computer1. POST /device_authorization2. device_code, user_code,address3. Shows "go to … andenter ABCD-EFGH"4. Opens the address, enters thecode, signs in5. POST /token (device_code) enloop6. authorization_pending, thenthe tokens
Text version of the diagram
  1. Device → Provider (OP) : POST /device_authorization
  2. Provider (OP) → Device : device_code, user_code, URL
  3. Device: Shows "go to … and enter ABCD-EFGH"
  4. Phone / computer → Provider (OP): Opens the address, enters the code, signs in
  5. Device → Provider (OP) : POST /token (device_code) in a loop
  6. Provider (OP) → Device: authorization_pending, then the tokens

Use when: Television, console, connected object, command-line tool.

What sets it apart: Sign-in happens on another device. The device polls the provider until validation.

ID-Kit can play it: test provider (your application against ID-Kit) and test application (your provider against ID-Kit).

Token exchange (RFC 8693) Specific cases

Exchange one token for another, for a different recipient.

API AProvider (OP)API B1. POST /token(grant_type=token-exchange,subject_token, audience=B)2. Checks rights and audience3. access token for API B4. Authorization: Bearer new token
Text version of the diagram
  1. API A → Provider (OP) : POST /token (grant_type=token-exchange, subject_token, audience=B)
  2. Provider (OP): Checks rights and audience
  3. Provider (OP) → API A: access token for API B
  4. API A → API B : Authorization: Bearer new token

Use when: An API that must call another one on behalf of the person, or microservices that propagate identity.

What sets it apart: Starts from a token already obtained, without a new sign-in. Can reduce the rights or change the audience.

ID-Kit can play it: test provider (your application against ID-Kit) and test application (your provider against ID-Kit).

Logout (RP-initiated and back-channel) Session

Close the session at the provider and notify the other applications.

BrowserApplication AProvider (OP)Application B1. Clicks "Sign out"2. 302 to /logout(id_token_hint,post_logout_redirect_uri)3. GET /logout4. Closes theprovider5. POST logout_token(back-channel)6. 302 to post_logout_redirect_uri
Text version of the diagram
  1. Browser → Application A: Clicks "Sign out"
  2. Application A → Browser : 302 to /logout (id_token_hint, post_logout_redirect_uri)
  3. Browser → Provider (OP) : GET /logout
  4. Provider (OP): Closes the provider session
  5. Provider (OP) → Application B : POST logout_token (back-channel)
  6. Provider (OP) → Browser : 302 to post_logout_redirect_uri

Use when: Any application with single sign-on (SSO): the logout must propagate.

What sets it apart: The back channel notifies server to server, without going through the browser (so it is reliable).

ID-Kit can play it: test provider (your application against ID-Kit) and test application (your provider against ID-Kit).

Introspection and revocation Check

Ask the provider whether a token is still valid, or invalidate it.

APIProvider (OP)1. POST /introspect (token)2. { "active": true, scope, exp,sub }3. POST /revoke (token)4. 200 : the token is invalid
Text version of the diagram
  1. API → Provider (OP) : POST /introspect (token)
  2. Provider (OP) → API : { "active": true, scope, exp, sub }
  3. API → Provider (OP) : POST /revoke (token)
  4. Provider (OP) → API: 200 : the token is invalid

Use when: An API that receives an opaque token, or that wants immediate revocation.

What sets it apart: A JWT can be verified alone by its signature; an opaque token requires this call.

ID-Kit can play it: test provider (your application against ID-Kit) and test application (your provider against ID-Kit).

private_key_jwt and JWT Bearer (RFC 7523) In ID-Kit: test provider

The client proves its identity with a JWT signed by its private key, rather than with a shared secret.

ServiceProvider (OP)1. Signs a JWT (iss, sub,aud, exp, jti)2. POST /token(client_assertion,client_assertion_type)3. Verifies the signature withthe client's public key4. access token
Text version of the diagram
  1. Service: Signs a JWT (iss, sub, aud, exp, jti)
  2. Service → Provider (OP) : POST /token (client_assertion, client_assertion_type)
  3. Provider (OP): Verifies the signature with the client's public key
  4. Provider (OP) → Service : access token

Use when: Banking, healthcare, sensitive APIs, enterprise integrations: no secret to store or rotate.

What sets it apart: Same exchange as client credentials, but authentication is a signed assertion (client_assertion).

ID-Kit can play it on the test provider side (declare your client's public key, type "Confidential by key"). Not yet on the test application side.

PAR and JAR (RFC 9126 and 9101) In ID-Kit

The authorization request is pushed server to server, instead of passing in clear in the address.

BrowserApplicationProvider (OP)1. POST /par (all theparameters, signed)2. request_uri (valid for a fewseconds)3. 302 to/authorize?request_uri=…4. GET /authorize?request_uri=…5. Sign-in then redirect with the code
Text version of the diagram
  1. Application → Provider (OP): POST /par (all parameters, signed)
  2. Provider (OP) → Application : request_uri (valid for a few seconds)
  3. Application → Browser : 302 to /authorize?request_uri=…
  4. Browser → Provider (OP) : GET /authorize?request_uri=…
  5. Provider (OP) → Browser: Sign-in then redirect with the code

Use when: FAPI requirements: prevent a parameter from being modified or read in the browser.

What sets it apart: The browser only carries an opaque request_uri.

ID-Kit can play it: test provider (your application against ID-Kit) and test application (your provider against ID-Kit).

JARM (signed authorization response) In ID-Kit (test provider)

The provider also signs its response: the code arrives in a JWT, not in clear in the address.

BrowserApplicationProvider (OP)1. 302 to/authorize?response_mode=jwt2. GET /authorize then sign-in3. Signs a JWT { iss, aud,code, state }4. Redirection to l’application ?response=JWT5. Forwards response6. Verifies the signature, iss,aud, then reads the code
Text version of the diagram
  1. Application → Browser : 302 to /authorize?response_mode=jwt
  2. Browser → Provider (OP) : GET /authorize then sign-in
  3. Provider (OP): Signs a JWT { iss, aud, code, state }
  4. Provider (OP) → Browser : Redirection to l’application ?response=JWT
  5. Browser → Application : Forwards response
  6. Application: Verifies the signature, iss, aud, then reads the code

Use when: FAPI 2.0, regulated sectors, protection against mix-up attacks between providers.

What sets it apart: A single "response" parameter (JWT signed with iss, aud, exp, code, state) replaces the plain parameters.

ID-Kit can play it on the test provider side (declare your client's public key, type "Confidential by key"). Not yet on the test application side.

DPoP (RFC 9449) In ID-Kit (test provider)

The token is bound to a key that only the client holds: a stolen token is unusable.

ApplicationProvider (OP)API1. Creates a key pair2. POST /token + DPoP header(signed proof)3. access token bound to the key(cnf.jkt)4. Authorization: DPoP token + new DPoP proof5. Verifies the proof and thelink with the key
Text version of the diagram
  1. Application: Creates a key pair
  2. Application → Provider (OP): POST /token + DPoP header (signed proof)
  3. Provider (OP) → Application: key-bound access token (cnf.jkt)
  4. Application → API : Authorization: DPoP token + new DPoP proof
  5. API: Verifies the proof and the link with the key

Use when: High security, exposed SPAs, sensitive APIs.

What sets it apart: Each call comes with a signed proof (DPoP header) proving possession of the key.

ID-Kit can play it on the test provider side (declare your client's public key, type "Confidential by key"). Not yet on the test application side.

CIBA (Client-Initiated Backchannel) In ID-Kit (test provider)

Authentication happens on the person's device, initiated by the server.

ApplicationProvider (OP)Phone1. POST /bc-authorize(login_hint, binding_message)2. auth_req_id3. Notification: "Authorize thispayment?"4. The person accepts5. POST /token (auth_req_id) enloop, or callback6. Tokens
Text version of the diagram
  1. Application → Provider (OP) : POST /bc-authorize (login_hint, binding_message)
  2. Provider (OP) → Application : auth_req_id
  3. Provider (OP) → Phone: Notification: "Authorize this payment?"
  4. Phone → Provider (OP): The person accepts
  5. Application → Provider (OP): POST /token (auth_req_id) in a loop, or callback
  6. Provider (OP) → Application : Tokens

Use when: Call centers, banks, payment confirmation by notification.

What sets it apart: No browser redirect: the provider contacts the person directly.

ID-Kit can play it on the test provider side (declare your client's public key, type "Confidential by key"). Not yet on the test application side.