OpenID Connect (OIDC) is the standard way to add secure authentication and single sign-on (SSO) to modern apps. This tutorial shows how OIDC works, what each token means, how the Authorization Code Flow works, and how to implement and test it in practice.
What Is OpenID Connect?
OpenID Connect is an authentication layer built on top of OAuth 2.0.
OAuth 2.0 answers:
Can this client access this resource?
OpenID Connect answers:
Who is the user?
OIDC adds identity-specific features to OAuth 2.0, including:
- ID tokens for user identity
-
Standard user claims like
email,name, andsub - Discovery metadata for provider configuration
- Single Sign-On across multiple apps
Use OpenID Connect when you need to log users in through an Identity Provider such as Google, Auth0, Okta, Microsoft, or your own authorization server.
Core OpenID Connect Concepts
Before implementing OIDC, understand the main components.
| Term | Meaning |
|---|---|
| Identity Provider, or IdP | Service that authenticates the user |
| Client, or Relying Party | Your app requesting authentication |
| End User | The person signing in |
| Authorization Server | Server that issues tokens |
| ID Token | JWT containing user identity claims |
| Access Token | Token used to call protected APIs |
| Discovery Document | Metadata endpoint describing OIDC configuration |
A common discovery URL looks like this:
https://idp.example.com/.well-known/openid-configuration
It usually returns endpoints such as:
{
"issuer": "https://idp.example.com",
"authorization_endpoint": "https://idp.example.com/authorize",
"token_endpoint": "https://idp.example.com/token",
"jwks_uri": "https://idp.example.com/.well-known/jwks.json"
}
Your app can use this metadata instead of hardcoding every endpoint.
Recommended Flow: Authorization Code Flow
For most web apps, use the Authorization Code Flow.
It is preferred because:
- Tokens are not returned directly in the browser URL
- The backend exchanges the code for tokens
- The app can validate tokens server-side
- It supports confidential clients with a
client_secret
For SPAs and mobile apps, use Authorization Code Flow with PKCE.
Avoid the Implicit Flow for new applications because it exposes tokens in the browser and is no longer recommended for modern OIDC implementations.
OpenID Connect Authentication Flow
Here is the standard Authorization Code Flow.
1. User Clicks Login
The user clicks a login button in your application.
Example:
Login with OpenID Connect
2. App Redirects to the Authorization Endpoint
Your app builds an authorization URL and redirects the user to the Identity Provider.
Required parameters usually include:
client_idredirect_uriscoperesponse_typestate
Example:
https://idp.example.com/authorize?
client_id=YOUR_CLIENT_ID
&redirect_uri=https://yourapp.com/callback
&scope=openid%20profile%20email
&response_type=code
&state=randomState123
The openid scope is required for OpenID Connect.
3. User Authenticates with the IdP
The Identity Provider displays a login page.
The user signs in and may be asked to consent to share profile information.
4. IdP Redirects Back to Your App
After successful authentication, the IdP redirects back to your redirect_uri.
Example:
https://yourapp.com/callback?code=AUTH_CODE&state=randomState123
Your app must verify that the returned state matches the original value. This helps protect against CSRF attacks.
5. Backend Exchanges the Code for Tokens
Your backend sends the authorization code to the token endpoint.
Example HTTP request:
POST /token HTTP/1.1
Host: idp.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTH_CODE
&redirect_uri=https://yourapp.com/callback
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
6. IdP Returns Tokens
The token endpoint returns an ID token and, usually, an access token.
Example response:
{
"access_token": "eyJ...abc",
"id_token": "eyJ...xyz",
"expires_in": 3600,
"token_type": "Bearer"
}
Depending on the provider and scopes, the response may also include a refresh_token.
7. App Validates the ID Token
Before logging in the user, validate the id_token.
At minimum, check:
- Signature
- Issuer,
iss - Audience,
aud - Expiration,
exp - Issued-at time,
iat - Nonce, if used
Only create a session after validation succeeds.
Understanding the ID Token
The ID token is a JWT that contains identity claims.
Example decoded payload:
{
"iss": "https://idp.example.com",
"sub": "1234567890",
"aud": "YOUR_CLIENT_ID",
"exp": 1712345678,
"iat": 1712341678,
"email": "user@example.com",
"name": "Jane Doe"
}
Important claims:
| Claim | Meaning |
|---|---|
iss |
Issuer, the Identity Provider |
sub |
Stable user ID at the provider |
aud |
Intended audience, usually your client ID |
exp |
Expiration timestamp |
iat |
Issued-at timestamp |
email |
User email, if requested |
name |
User name, if requested |
Do not trust the ID token just because it can be decoded. A JWT can be decoded without being valid. Always verify the signature and claims.
Hands-On Example with Python
The following example shows the basic OIDC steps in Python without relying on a provider-specific SDK.
Install dependencies:
pip install requests PyJWT cryptography
Step 1: Build the Authorization URL
import urllib.parse
params = {
"client_id": "YOUR_CLIENT_ID",
"redirect_uri": "https://yourapp.com/callback",
"response_type": "code",
"scope": "openid profile email",
"state": "randomState123"
}
auth_url = "https://idp.example.com/authorize?" + urllib.parse.urlencode(params)
print(auth_url)
Redirect the user to the generated auth_url.
Step 2: Exchange the Authorization Code for Tokens
After the user returns to your callback URL, extract the code query parameter and exchange it for tokens.
import requests
token_data = {
"grant_type": "authorization_code",
"code": "AUTH_CODE",
"redirect_uri": "https://yourapp.com/callback",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET"
}
resp = requests.post("https://idp.example.com/token", data=token_data)
resp.raise_for_status()
tokens = resp.json()
print(tokens)
Example output:
{
"access_token": "eyJ...abc",
"id_token": "eyJ...xyz",
"expires_in": 3600,
"token_type": "Bearer"
}
Step 3: Decode the ID Token for Inspection
For debugging only, you can decode the token without validating it:
import jwt
id_token = tokens["id_token"]
decoded = jwt.decode(
id_token,
options={"verify_signature": False}
)
print(decoded)
Do not use this approach for production authentication.
Step 4: Validate the ID Token Signature and Claims
In production, fetch the provider’s JWKS and verify the token.
import jwt
from jwt import PyJWKClient
id_token = tokens["id_token"]
jwks_url = "https://idp.example.com/.well-known/jwks.json"
jwks_client = PyJWKClient(jwks_url)
signing_key = jwks_client.get_signing_key_from_jwt(id_token)
claims = jwt.decode(
id_token,
signing_key.key,
algorithms=["RS256"],
audience="YOUR_CLIENT_ID",
issuer="https://idp.example.com"
)
print(claims)
If validation succeeds, you can use claims such as sub, email, and name to create or update the local user session.
Using the Access Token
The access token is for API authorization.
Example API call:
headers = {
"Authorization": f"Bearer {tokens['access_token']}"
}
api_resp = requests.get(
"https://api.example.com/me",
headers=headers
)
print(api_resp.json())
Your API should validate the access token according to your authorization server’s rules before returning protected data.
Practical Use Cases
1. Single Sign-On Across Apps
Use OIDC when multiple apps should trust the same Identity Provider.
Typical implementation:
- Register each app as a client in the IdP.
- Configure allowed redirect URIs.
- Use the Authorization Code Flow.
- Validate ID tokens in each app.
- Create app-specific sessions after successful validation.
2. Secure API Authentication
Use the ID token to authenticate the user and the access token to authorize API calls.
A common pattern:
- User signs in with OIDC.
- App receives an access token.
- App sends the access token to the API.
- API validates the token.
- API applies authorization rules.
3. Social Login
OIDC powers common login options such as:
- Login with Google
- Login with Microsoft
- Login with Okta
- Login with Auth0
The implementation pattern is the same:
- Register your app with the provider.
- Configure redirect URIs.
- Request
openid profile email. - Validate the returned ID token.
- Create or update the local user account.
4. Mobile App Authentication
Mobile apps can use OIDC with redirects and deep links.
For mobile apps and public clients, use Authorization Code Flow with PKCE instead of relying on a client secret.
Testing and Debugging OIDC APIs with Apidog
When developing OpenID Connect integrations, API testing is important because most of the flow depends on HTTP requests and token responses.
Apidog is a spec-driven API development platform for API design, mocking, and testing.
You can use it to:
- Send token endpoint requests
- Inspect JSON responses
- Test secured API endpoints with bearer tokens
- Mock IdP-like endpoints while developing
- Document OIDC-secured APIs for frontend and backend teams
A practical testing workflow:
- Create a request for the token endpoint.
- Add form fields such as
grant_type,code,redirect_uri,client_id, andclient_secret. - Send the request and inspect the token response.
- Copy the
access_token. - Use it as a bearer token in protected API requests.
- Validate expected success and failure responses.
Best Practices
Use this checklist when implementing OpenID Connect:
- Always use HTTPS.
- Use Authorization Code Flow for web apps.
- Use Authorization Code Flow with PKCE for SPAs and mobile apps.
- Validate the ID token signature.
- Validate
iss,aud,exp, andiat. - Verify
stateon callback. - Store
client_secretsecurely. - Do not expose tokens in URLs.
- Do not trust decoded JWTs without verification.
- Handle expired and revoked sessions.
- Keep OIDC libraries and dependencies updated.
Conclusion
OpenID Connect gives your application a standardized way to authenticate users and integrate SSO.
To implement it:
- Register your app with an Identity Provider.
- Configure redirect URIs.
- Build the authorization URL.
- Exchange the authorization code for tokens.
- Validate the ID token.
- Create a local session.
- Use the access token for protected API calls when needed.
- Test the full flow before shipping.
Once this flow is working, you can expand into advanced OIDC features such as discovery, PKCE, refresh tokens, federated identity, and dynamic client registration.
Top comments (0)