OpenID Connect & OAuth2 Client
oidc-client is a comprehensive JavaScript client library for OpenID Connect (OIDC) and OAuth2, designed to facilitate secure authentication and authorization in web applications. It handles complex OAuth2 flows, including Authorization Code Flow with PKCE, implicit flow, and refresh token management, abstracting away much of the underlying protocol complexity. Developed by IdentityModel, it maintains a strong focus on security and adherence to OIDC/OAuth2 specifications. The current stable version is 1.11.5, with an active development cycle characterized by frequent bug fix releases and minor feature updates approximately every 1-2 months, as evidenced by recent patch versions. Key differentiators include its robust handling of session management, silent token renewal, and extensive configurability, making it suitable for a wide range of single-page applications and client-side integrations.
Common errors
-
TS typings error in getToken for optional param
cause Incorrect or missing TypeScript definitions for optional parameters in the `getToken` method prior to version 1.11.2.fixUpgrade to `oidc-client@1.11.2` or newer to get the corrected typings for the `getToken` method. -
New TypeScript typings don't allow optionless UserManager
cause The TypeScript definitions were updated in version 1.10.1 to require a `UserManagerSettings` object when instantiating `UserManager`, even if empty.fixInstantiate `UserManager` with an empty object if no settings are needed: `new UserManager({});` -
TypeError: Cannot read property 'id' of undefined in validateSignoutResponse
cause This error, reported in versions prior to 1.9.1, indicates that the sign-out response validation logic failed to find an expected 'id' property, likely due to an invalid or malformed sign-out response from the OIDC provider.fixEnsure your OIDC provider is returning a correctly formatted sign-out response. Upgrade to `oidc-client@1.9.1` or newer which includes a fix for this specific validation issue. -
Angular 8 build error: Cannot read property 'id' of undefined or similar build failures related to `oidc-client`.
cause Specific build incompatibilities or incorrect module resolution issues were reported with Angular 8 in versions prior to 1.10.0.fixUpgrade `oidc-client` to version 1.10.0 or newer. This version included specific fixes to address Angular 8 build errors, likely related to TypeScript configurations or module bundling.
Warnings
- gotcha Metadata merging issues can lead to incorrect configuration. Specifically, `metadataSeed` was improperly merged and returned in versions prior to 1.11.5, potentially causing runtime errors or unexpected behavior during discovery.
- gotcha Authentication Code Flow with PKCE (Proof Key for Code Exchange) was not supported for popup windows in versions prior to 1.11.3, limiting flexibility for certain authentication UX patterns.
- breaking The `getEpochTime` method was removed from `OidcClientSettings` in version 1.11.1. If you were customizing epoch time calculation through this setting, your application will break.
- breaking TypeScript typings for `UserManager` in versions prior to 1.10.1 no longer allowed instantiation without options. This broke existing TypeScript code that initialized `UserManager` without an explicit settings object.
- gotcha The `SessionMonitor` component could cause warnings when used in conjunction with the Bluebird promise library. This was a specific interaction issue reported in version 1.11.1.
Install
-
npm install oidc-client -
yarn add oidc-client -
pnpm add oidc-client
Imports
- UserManager
const UserManager = require('oidc-client').UserManagerimport { UserManager } from 'oidc-client' - WebStorageStateStore
const WebStorageStateStore = require('oidc-client').WebStorageStateStoreimport { WebStorageStateStore } from 'oidc-client' - Log
const Log = require('oidc-client').Logimport { Log } from 'oidc-client' - OidcClient
const OidcClient = require('oidc-client').OidcClientimport { OidcClient } from 'oidc-client'
Quickstart
import { UserManager, WebStorageStateStore, Log } from 'oidc-client';
Log.logger = console;
Log.level = Log.INFO;
const settings = {
authority: 'https://demo.duendesoftware.com/', // Your OIDC provider authority
client_id: 'interactive.public', // Your client ID
redirect_uri: 'http://localhost:3000/callback', // Your app's redirect URI
response_type: 'code',
scope: 'openid profile api offline_access',
post_logout_redirect_uri: 'http://localhost:3000/', // Where to go after logout
userStore: new WebStorageStateStore({ store: window.localStorage }),
automaticSilentRenew: true,
// Optional: configure popup for signin/signout if needed
// popup_redirect_uri: 'http://localhost:3000/popup.html',
// popup_post_logout_redirect_uri: 'http://localhost:3000/popup.html',
};
const userManager = new UserManager(settings);
async function signIn() {
try {
await userManager.signinRedirect();
} catch (error) {
Log.error("Signin error", error);
}
}
async function signOut() {
try {
await userManager.signoutRedirect();
} catch (error) {
Log.error("Signout error", error);
}
}
async function getUser() {
try {
const user = await userManager.getUser();
if (user) {
Log.info("User loaded:", user);
console.log('Access Token:', user.access_token);
console.log('ID Token:', user.id_token);
} else {
Log.info("No user logged in.");
}
return user;
} catch (error) {
Log.error("Error getting user:", error);
return null;
}
}
// Example usage (e.g., in a SPA entry point)
async function initializeApp() {
const path = window.location.pathname;
if (path === '/callback') {
try {
const user = await userManager.signinRedirectCallback();
Log.info("Signin redirect callback processed. User:", user);
window.history.replaceState({}, document.title, '/'); // Clean up URL
} catch (error) {
Log.error("Error in signin redirect callback", error);
}
} else {
const user = await getUser();
if (!user) {
console.log('No user, initiating sign-in...');
signIn();
} else {
console.log('User already logged in.');
// For demonstration purposes, you might want to call sign out later
// setTimeout(signOut, 60000);
}
}
}
initializeApp();