Federate an App with Okta (OIDC Authorization Code + PKCE)

Beginner45–60 minLast reviewed: 2026-02-01

This tutorial walks you through a production-realistic OIDC federation setup using Okta.

You’ll create an Okta OIDC app integration, implement Authorization Code + PKCE, validate an ID token, and protect an authenticated route.

What you’ll build

  • A minimal web app that redirects to Okta for login
  • A callback handler that exchanges the code for tokens (with PKCE)
  • ID token validation (issuer, audience, expiry, nonce)
  • A protected page that shows the authenticated subject + claims

Prerequisites

  • Okta developer org
  • Node.js 20+ (22 is fine)
  • Basic comfort with HTTP redirects

Architecture overview

Diagram

Step 1 — Create the Okta OIDC app integration

  1. In Okta Admin Console, create an OIDC application integration.

  2. Choose:

  • Web Application
  • Grant type: Authorization Code
  • (If available) require PKCE
  1. Configure redirect URIs:
  • http://localhost:3000/callback
  1. Copy these values:
  • Issuer (or Okta domain + authorization server)
  • Client ID
  • Client Secret (if you’re using a confidential client)

Step 2 — Create the demo app (skeleton)

You can implement this tutorial in whatever stack you prefer. The key parts are the same:

  • /login endpoint that builds an authorization request
  • /callback endpoint that exchanges code for tokens
  • /me endpoint that requires a session

At minimum, store:

  • code_verifier (server-side)
  • state and nonce (server-side)
  • a server session cookie for the user

Step 3 — Generate PKCE + redirect to Okta

When the user clicks Login:

  • generate code_verifier (random)
  • derive code_challenge (S256)
  • generate state (CSRF)
  • generate nonce (bind to ID token)

Then redirect to Okta’s authorize endpoint.

Common pitfall: if you don’t validate state, you’re vulnerable to login CSRF.

Step 4 — Handle callback and exchange code for tokens

On the callback:

  • validate state
  • send token request with:
    • grant_type=authorization_code
    • code
    • redirect_uri
    • code_verifier

Okta returns (typically):

  • id_token
  • access_token
  • optionally refresh_token

Step 5 — Validate the ID token (minimum checks)

At minimum validate:

  • signature (fetch JWKs via discovery)
  • iss matches your issuer
  • aud contains your client ID
  • exp not expired (account for clock skew)
  • nonce matches

Common pitfall: only decoding the JWT and trusting its contents.

Step 6 — Create a session and protect a route

Once ID token validation passes:

  • create a server session record
  • set an HttpOnly cookie
  • protect your /me route by checking the session

Troubleshooting

  • redirect_uri mismatch: exact string mismatch between app and Okta config
  • invalid_client: wrong client auth method (secret vs none)
  • invalid_grant: code used twice, wrong code_verifier, or wrong redirect_uri
  • JWK fetch failures: wrong issuer / network

Hardening / production notes

  • Prefer PKCE everywhere (including public clients)
  • Use short-lived access tokens + refresh token rotation where appropriate
  • Be explicit about scopes and claims
  • Log auth failures with correlation IDs (but don’t log tokens)

Cleanup

  • Delete the Okta app integration when you’re done (or keep it for future labs).

Where to go next