Live demo, no account needed

See a fake identity provider handle real OIDC flows.

Every case below signs in for real against HeyIdentity: you pick a test user instead of typing a password, and come back here with real, signed tokens. Plain browser JavaScript, no frameworks, no client secret.

Pick a case

Cases A, B, E and F share one sign-in against a Generic configuration, so once you're signed in you can try all of them. Case D signs in against a Microsoft-profile configuration through Entra-shaped URLs.

A

SPA sign-in with PKCE

Authorization Code with PKCE (S256) and state, as a public client. You'll see the decoded ID token and what happened at each step.

B

Roles: admin vs. user

Sign in once as Avery Admin and once as Riley User. The same app gets different roles, and the simulated admin area is allowed or denied.

D

Entra ID drop-in

The Microsoft profile serves Entra ID v2.0 URLs. Tokens carry tid, oid, ver and scp, so MSAL and Microsoft.Identity.Web work unchanged.

E

Refresh token and userinfo

Asking for offline_access returns a refresh token. Redeem it for new tokens, and call the userinfo endpoint with the access token.

F

Sign-out

Sign out through the advertised end_session_endpoint with id_token_hint, post_logout_redirect_uri and state.

Signing in against , client heyidentity-demo.

How it works

Authorization Code with PKCE is the recommended flow for browser apps. There's no client secret, so there's nothing to leak.

1

Discover

The demo fetches the configuration's discovery document and takes every endpoint URL from it. No endpoint is hardcoded.

2

Pick a user

HeyIdentity shows the configuration's test users. Picking one is the whole "login". Users, roles and claims are configured per configuration.

3

Exchange the code

Back here, the code and the original PKCE verifier are posted to the token endpoint. The tokens never leave this browser tab.

The code

This is the actual flow the demo runs (js/demo.js). Point it at your own configuration's discovery URL after you sign up.

1. Discover endpoints

// Generic profile: /t/{tenantRouteId}/c/{configurationId}/.well-known/openid-configuration
// Microsoft profile: /{configurationId}/v2.0/.well-known/openid-configuration
const disco = await fetch(
  'https://app.heyidentity.dev/t/0f88f277-dad3-4f86-a66f-f6fc918db2ac/c/6cdf13d4-1c4e-4cf4-a1c1-9e1fc6009026/.well-known/openid-configuration'
).then(r => r.json());

2. Redirect with a PKCE challenge

const verifier  = base64url(crypto.getRandomValues(new Uint8Array(32)));
const challenge = base64url(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier)));
const state     = base64url(crypto.getRandomValues(new Uint8Array(16)));
sessionStorage.setItem('pkce', JSON.stringify({ verifier, state }));

location.assign(disco.authorization_endpoint + '?' + new URLSearchParams({
  response_type: 'code',
  client_id: 'heyidentity-demo',
  redirect_uri: location.origin + '/callback.html',
  scope: 'openid profile email offline_access',
  state,
  code_challenge: challenge,
  code_challenge_method: 'S256',
}));

3. Exchange the code on the callback page

const query = new URLSearchParams(location.search);
const { verifier, state } = JSON.parse(sessionStorage.getItem('pkce'));
if (query.get('state') !== state) throw new Error('State mismatch');

const tokens = await fetch(disco.token_endpoint, {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    client_id: 'heyidentity-demo',
    code: query.get('code'),
    redirect_uri: location.origin + '/callback.html',
    code_verifier: verifier,
  }),
}).then(r => r.json());
// tokens.id_token, tokens.access_token, tokens.refresh_token
Your own setup: after signing up you get your own tenant, a management link and a starter configuration. Add your client's redirect URIs and your test users there, then use your configuration's discovery URL above.