On this page
OAuth2 and OpenID Connect
OAuth2 is an authorization framework (allowing apps to access your resources on your behalf), while OIDC adds a layer of authentication on top (allowing apps to verify your identity). Authorization code + PKCE is the current best practice; the implicit flow is dead.
Overview
OAuth2 (RFC 6749, 2012) is the standard framework for internet authorization—"allowing third-party apps to access my resources without needing my password." The core flow is Authorization Code + PKCE: the browser redirects to the authorization server → the user logs in → the browser returns with a code → the client exchanges the code for an access token. OIDC (OpenID Connect, 2014) adds identity authentication (id_token) on top of OAuth2, becoming the foundation for "Login with Google/GitHub." JWT is the most common format for OAuth2 access tokens—self-contained, verifiable, and stateless.
OAuth2: Authorization (Not Authentication)
Four roles:
Resource Owner: The user
Client: Third-party application
Authorization Server: Authorization server
Resource Server: API server
Authorization Code + PKCE (the only recommended web flow):
1. Client: Generate code_verifier (random), code_challenge = SHA256(verifier)
2. Browser redirect:
GET /authorize?response_type=code
&client_id=grafana
&redirect_uri=https://grafana.example.com/login/callback
&scope=openid profile email
&state=random123
&code_challenge=<base64url(challenge)>
&code_challenge_method=S256
3. User logs in + consents
4. Browser redirects back: https://grafana.example.com/login/callback?code=AUTH_CODE&state=random123
5. Client → Authorization Server (backchannel):
POST /token
grant_type=authorization_code
&code=AUTH_CODE
&redirect_uri=...
&code_verifier=<verifier> ← server verifies SHA256(verifier)==challenge
6. Response: { "access_token", "refresh_token", "id_token", "token_type":"Bearer", "expires_in":3600 }
7. Client: Requests API using access_token (Authorization: Bearer <token>)
Why PKCE is Needed
In traditional flows, the code can be intercepted (the redirect URI for a mobile app might be registered by another app). PKCE ensures that even if the code is leaked, the token cannot be exchanged without the code_verifier.
JWT
Format: base64(header).base64(payload).signature
Header: {"alg":"RS256","typ":"JWT","kid":"key-2025"}
Payload (claims):
iss: Issuer
sub: User ID (subject)
aud: Audience (who this token is for)
exp: Expiration time (unix)
iat: Issued at time
email, name, groups: Custom claims
Signature: RSA-SHA256(base64(header)+"."+base64(payload))
Verification:
1. Fetch JWKS (https://auth.example.com/.well-known/jwks.json) → get the public key corresponding to the kid
2. Verify the signature
3. Check exp (not expired), aud (this token is for me), iss (from a trusted issuer)
OpenID Connect (OIDC)
OIDC = OAuth2 + User Identity (id_token):
id_token (JWT): Sent to the client to prove "who the user is" (not for calling APIs)
access_token: Sent to the API to prove "the client has permission to access" (does not contain user info)
Client Credentials (Machine-to-Machine)
POST /token
grant_type=client_credentials
&client_id=my-app
&client_secret=secret
→ { "access_token":"...", "expires_in":3600 }
→ No user involvement
References
- jwt.io: Debug JWTs
- Keycloak: Open source identity provider
- OIDC playground: openidconnect.net
Keywords: OAuth2, PKCE, JWT, OIDC, id_token, client credentials, JWKS, Keycloak