DEV Community

Preecha
Preecha

Posted on

OpenID Connect Tutorial: Complete Step-by-Step Guide

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.

Try Apidog today

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, and sub
  • 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
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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_id
  • redirect_uri
  • scope
  • response_type
  • state

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

Example output:

{
  "access_token": "eyJ...abc",
  "id_token": "eyJ...xyz",
  "expires_in": 3600,
  "token_type": "Bearer"
}
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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())
Enter fullscreen mode Exit fullscreen mode

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:

  1. Register each app as a client in the IdP.
  2. Configure allowed redirect URIs.
  3. Use the Authorization Code Flow.
  4. Validate ID tokens in each app.
  5. 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:

  1. User signs in with OIDC.
  2. App receives an access token.
  3. App sends the access token to the API.
  4. API validates the token.
  5. 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:

  1. Register your app with the provider.
  2. Configure redirect URIs.
  3. Request openid profile email.
  4. Validate the returned ID token.
  5. 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:

  1. Create a request for the token endpoint.
  2. Add form fields such as grant_type, code, redirect_uri, client_id, and client_secret.
  3. Send the request and inspect the token response.
  4. Copy the access_token.
  5. Use it as a bearer token in protected API requests.
  6. 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, and iat.
  • Verify state on callback.
  • Store client_secret securely.
  • 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:

  1. Register your app with an Identity Provider.
  2. Configure redirect URIs.
  3. Build the authorization URL.
  4. Exchange the authorization code for tokens.
  5. Validate the ID token.
  6. Create a local session.
  7. Use the access token for protected API calls when needed.
  8. 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)