Skip to content
Language:en Author:Laborci Gergely
identity

OAuth 2.0 and OpenID Connect

Objectives

By the end of the lesson, you can say what OAuth 2.0 is for and what OpenID Connect is for, you can list the actors of OAuth, you can describe the steps of the authorization code flow, and you can tell an access token from an ID token.

Why don't we hand over the password?

Kurzuspont would like to save the student's timetable into an external calendar. It would be a bad solution to ask for the student's password at the calendar provider: Kurzuspont could then do anything on the student's behalf, and could even leak the password. The solution is delegated access: the student logs in at the calendar provider, decides there what to allow Kurzuspont, and Kurzuspont receives a token with limited authorization. The password stays with the calendar provider. The OAuth 2.0 framework is for this.

flowchart LR
    U[Student] --> A[Kurzuspont]
    A -->|asks for access| I[Authorization provider]
    U -->|decides there| I
    I -->|access token| A
    A -->|token in the request| N[Calendar API]

The actors of OAuth 2.0

RFC 6749 distinguishes four roles:

Role Name in the RFC Example
The party granting access resource owner the student
The application requesting access client Kurzuspont
The server issuing the token authorization server the authorization server of the calendar provider
The server holding the protected resource resource server the calendar's API

Separating the roles helps in understanding that a token is not a general "I am logged in everywhere" proof: it is for reaching a defined resource, according to the given permission and validity conditions.

The authorization code flow

According to RFC 6749 the steps of the authorization code flow are:

  1. The client directs the user to the authorization server, giving its identifier, the requested scope, and a redirect address.
  2. The authorization server identifies the user, who grants or denies access.
  3. If they grant it, the server redirects the user back to the client's address with an authorization code.
  4. The client sends the code to the token endpoint of the authorization server, authenticating itself meanwhile.
  5. The server checks the code and issues the access token (and optionally a refresh token).
sequenceDiagram
    actor H as Student
    participant K as Kurzuspont (client)
    participant E as Authorization server
    participant N as Calendar API
    H->>K: Save the timetable to the calendar
    K-->>H: Redirect to the authorization server
    H->>E: Logs in, grants permission
    E-->>H: Redirect to Kurzuspont + authorization code
    H->>K: Authorization code
    K->>E: Redeem the code (request the token)
    E-->>K: Access token
    K->>N: Request + token
    N-->>K: Result of the calendar operation

The diagram is conceptual, not a complete sequence of protocol messages. The code passes through the browser, while the token travels directly between the client and the authorization server, so only the short-lived code reaches the browser.

PKCE: protection against interception of the code

The authorization code can pass through a channel (the redirect address) that another program can intercept. PKCE (Proof Key for Code Exchange, RFC 7636) protects against this with a per-request secret: the client makes a random code_verifier, sends a code_challenge formed from its SHA-256 digest in the first request, and the original verifier when redeeming the code. The server recomputes the digest and compares; if it differs, it rejects. An intercepted code cannot thus be redeemed without the verifier.

We tried it with the example values of RFC 7636 (Node.js crypto):

code_verifier  = dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
code_challenge = BASE64URL(SHA256(code_verifier)) = E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM

The result equals the code_challenge value in the RFC. According to RFC 9700 (the OAuth 2.0 security recommendation) PKCE is mandatory for public clients (for example mobile and browser applications), recommended for confidential clients as well, and the S256 method must be used. The same RFC also says that clients should not use the implicit flow, in which the access token arrives directly in the authorization response, because it can leak through the URL, the history, or the Referer header.

OAuth 2.0 by itself is not a login

OAuth 2.0 tells how a client can obtain limited access to a resource. It does not tell who the user is for the client. An access token must therefore not be interpreted automatically as proof of identity. The form of the token is not necessarily a JWT either: it can be a value opaque to the client.

OpenID Connect: identity for the client

According to the specification of the OpenID Foundation, OpenID Connect (OIDC) is a simple identity layer on top of OAuth 2.0: it allows the client to verify who the user is, based on the authentication performed by the authorization server. Its most important device is the ID token (ID stands for "identity"), which is a JWT (7.3) and contains claims about the authentication of the user:

Claim Meaning
iss (issuer) Who issued the token (an https address).
sub (subject) The identifier of the user at the issuer, locally unique and never reused.
aud (audience) Whom it is for: it must contain the client's identifier.
exp (expiration) Until when it can be accepted.

The client must check the ID token for its own purpose (issuer, audience, expiry, signature). It does not replace the access token meant for an API.

flowchart TD
    T[What does the application want?] -->|use an external API| O[OAuth 2.0: delegated access]
    T -->|log the user in| I[OpenID Connect: identity]

The application's own session can also get a lifecycle separate from the login at the external provider. After a successful external authentication the local application must still decide what resources of its own it gives the recognized user access to. External identification does not give automatic authorization (7.4).

Worked example: two tasks in Kurzuspont

Task Protocol What does Kurzuspont receive?
The student logs in with their university identifier OpenID Connect An ID token: who the student is (sub), who issued it (iss).
Saving the timetable into the student's external calendar OAuth 2.0 An access token for the calendar API, with a limited scope.

In one user experience the two flows can be joined ("Log in and authorize the calendar"), but conceptually they differ: the first identifies, the second delegates access. In both, Kurzuspont's own authorization decision (7.4) remains in force.

Common misconceptions

Statement Clarification
"OAuth 2.0 by itself is a login protocol." Its primary goal is delegated access; for identity, OIDC provides the protocol.
"The access token tells the client who the user is." It represents the access meant for the resource server, it is not an identity claim.
"Any API can be called with an ID token." The ID token is an authentication claim addressed to the client.
"After an external login every local operation is allowed." The local service's own authorization decision is needed.
"PKCE is needed only for mobile apps." According to RFC 9700 it is mandatory for public clients, recommended for the others.

In brief

  • OAuth 2.0 is delegated access: the client gets a limited token without the password.
  • Actors: resource owner, client, authorization server, resource server.
  • The authorization code flow should be used with PKCE; the implicit flow is not recommended.
  • On top of OAuth, OIDC gives identity with the ID token (JWT: iss, sub, aud, exp).
  • The purpose and audience of the access token and the ID token differ.

Review questions

  1. Why don't we hand over the calendar password to Kurzuspont?
  2. What is the difference between an access token and an ID token?
  3. What does PKCE protect?
  4. Why is a bare OAuth 2.0 access token not good for login?

Learning resources

Prerequisites (3)

  • authentication
  • authorization
  • token

Teaches (2)

  • OAuth 2.0
  • OpenID Connect