Test OpenID Connect flows with Zero IDS
Follow these scenarios to test different OIDC flows. Configure the client in Settings before testing.
Use Case: The most secure and common flow for server-side web applications. The application (client) exchanges a temporary authorization code for an access token directly with the server (back-channel), ensuring tokens are never exposed to the user's browser.
Create a new Client in the Console with these exact settings:
client_secret_basiccodeauthorization_codeopenid, profile, email, offline_accesshttp://localhost:3001/callbackclient_secret_basicAuthorization Code (code)const { Issuer } = require('openid-client');
// 1. Discover Issuer
const issuer = await Issuer.discover('http://localhost:3000');
// 2. Initialize Client
const client = new issuer.Client({
client_id: 'client-scenario-1',
client_secret: 'secret-scen1',
redirect_uris: ['http://localhost:3001/callback'],
response_types: ['code']
});
// 3. Generate Auth URL (Start Login)
const code_verifier = generators.codeVerifier();
const code_challenge = generators.codeChallenge(code_verifier);
const authUrl = client.authorizationUrl({
scope: 'openid profile email offline_access',
code_challenge,
code_challenge_method: 'S256'
});
// -> Redirect user to authUrl
// 4. Handle Callback (After Redirect)
const params = client.callbackParams(req);
const tokenSet = await client.callback('http://localhost:3001/callback', params, { code_verifier });
console.log('Access Token:', tokenSet.access_token);
code.code for an access_token, id_token, and refresh_token.Use Case: Used when a frontend application (SPA) needs an ID Token immediately for UI customization (e.g., showing user avatar) while the backend securely handles the Access Token exchange using the code. This allows for immediate UI updates without waiting for a backend round-trip.
Create a new Client (or update existing) with these settings:
client_secret_basiccode and id_tokenauthorization_code, implicitopenid, profile, emailhttp://localhost:3001/callbackclient_secret_basicHybrid (code + id_token)// Client Setup
const client = new issuer.Client({
client_id: 'client-scenario-2',
client_secret: 'secret-scen2',
redirect_uris: ['http://localhost:3001/callback'],
response_types: ['code id_token'] // Hybrid
});
// Generate Auth URL
const authUrl = client.authorizationUrl({
scope: 'openid profile email',
response_type: 'code id_token',
response_mode: 'form_post', // Required for Hybrid/Implicit
nonce: generators.nonce()
});
// Handle Callback
const params = client.callbackParams(req);
const tokenSet = await client.callback('http://localhost:3001/callback', params, { nonce });
// tokenSet.id_token is available immediately
// tokenSet.access_token is exchanged via code
code and an id_token (usually in the URL fragment or form post).id_token immediately.code for the full token set (access_token, refresh_token).Use Case: Historically used for Single Page Applications (SPAs) where tokens were returned directly to the browser. Not Recommended for new applications due to security risks (tokens exposed in URL). Modern SPAs should use Authorization Code Flow with PKCE instead.
Create a new Client with these settings:
client_secret_basic (or None for public clients)id_token OR token (or both)implicitopenid, profilehttp://localhost:3001/callbackclient_secret_basicImplicit (id_token)// Client Setup
const client = new issuer.Client({
client_id: 'client-scenario-3',
client_secret: 'secret-scen3',
redirect_uris: ['http://localhost:3001/callback'],
response_types: ['id_token']
});
// Generate Auth URL
const authUrl = client.authorizationUrl({
scope: 'openid profile',
response_type: 'id_token',
response_mode: 'fragment', // Tokens returned in URL fragment
nonce: generators.nonce()
});
// Note: Implicit flow callbacks are typically handled
// entirely in the browser (JavaScript), not the server.
id_token directly in the URL fragment (#id_token=...).Use Case: Used for backend-to-backend communication where no user is present (e.g., a daemon service, cron job, or internal microservice). The application authenticates itself to access resources on its own behalf.
Create a new Client with these settings:
client_secret_postclient_credentialsapi:read)client_secret_post// Client Setup
const client = new issuer.Client({
client_id: 'client-scenario-4',
client_secret: 'secret-scen4',
token_endpoint_auth_method: 'client_secret_post'
});
// Request Token Directly
const tokenSet = await client.grant({
grant_type: 'client_credentials',
scope: 'api:read'
});
console.log('Access Token:', tokenSet.access_token);
/oidc/token endpoint.access_token immediately (JSON response).Use Case: Allows an application to obtain a new Access Token without requiring the user to log in again. This is critical for maintaining a seamless user experience in long-running sessions.
Ensure your Client has these settings enabled:
refresh_tokenoffline_accessoffline_access scope.// Assuming you have an expired tokenSet with a refresh_token
const refreshToken = tokenSet.refresh_token;
// Refresh the Token
const newTokenSet = await client.refresh(refreshToken);
console.log('New Access Token:', newTokenSet.access_token);
console.log('New Refresh Token:', newTokenSet.refresh_token);
POST /oidc/token request with grant_type=refresh_token and the stored refresh_token.access_token (and optionally a new refresh_token).Use Case: Used by Resource Servers (APIs) to validate an incoming Access Token. It checks if the token is active, not expired, and not revoked, and retrieves metadata like scopes and subject.
// Introspect a token (access_token or refresh_token)
const token = 'eyJhbGciOiJ...';
const result = await client.introspect(token, 'access_token');
console.log('Active:', result.active);
console.log('Scopes:', result.scope);
POST /oidc/token/introspection request to the server.active: true (if valid), exp (expiration), scope, and other metadata.Use Case: Allows a client to explicitly invalidate a token before its natural expiration. This is important for "Sign Out" functionality or when a device is lost/compromised.
// Revoke a token
const token = 'eyJhbGciOiJ...';
await client.revoke(token, 'access_token');
console.log('Token revoked successfully');
POST /oidc/token/revocation request to the server.200 OK.Use Case: A standard OIDC endpoint that allows the client to retrieve the user's profile information (claims) using a valid Access Token. Useful when the ID Token doesn't contain all necessary user details.
profile and email scopes.// Fetch UserInfo using Access Token
const accessToken = tokenSet.access_token;
const userInfo = await client.userinfo(accessToken);
console.log('User Email:', userInfo.email);
console.log('User Sub:', userInfo.sub);
GET /oidc/me request with the Access Token in the Authorization header.sub, name, email, picture).Use Case: Allows the application (Relying Party) to initiate a logout process at the Identity Server. This ensures the user is logged out of the SSO session, not just the local application session.
// Generate Logout URL
const logoutUrl = client.endSessionUrl({
id_token_hint: tokenSet.id_token,
post_logout_redirect_uri: 'http://localhost:3001'
});
// Redirect user to logoutUrl
res.redirect(logoutUrl);
end_session_endpoint.