React OIDC Context
react-oidc-context is a lightweight authentication library for React Single Page Applications (SPAs) that leverages the React Context API for state management, built on top of the `oidc-client-ts` library. The current stable version is 3.3.1. The package maintains a fairly active release cadence, with frequent bugfix and minor releases, and significant major versions introducing breaking changes as the underlying `oidc-client-ts` library evolves. It differentiates itself by providing convenient React hooks (`useAuth`) and Higher-Order Components (`withAuthenticationRequired`) to integrate OpenID Connect and OAuth2 authentication flows seamlessly into React components, handling aspects like token renewal and redirect callbacks without requiring manual route setup. It ships with full TypeScript support, making it suitable for modern React development.
Common errors
-
TypeError: crypto.subtle is undefined
cause The application is running in an insecure context (HTTP) where the Web Cryptography API (`crypto.subtle`) is not available.fixServe your application over HTTPS. For local development, configure your server to use SSL/TLS or use a tool like `mkcert`. -
Token renewal (signinSilent) is not working after a successful login and subsequent page refresh.
cause The OIDC response payload remains in the URL after a successful login, preventing `oidc-client-ts` from correctly initiating silent renewals.fixImplement the `onSigninCallback` function in your `oidcConfig` to clear the URL parameters, e.g., `onSigninCallback: () => { window.history.replaceState({}, document.title, window.location.pathname); }`. -
Error: require() not supported for ESM module 'react-oidc-context'
cause Attempting to use CommonJS `require()` syntax to import `react-oidc-context`, which is an ESM-only module since version 3.0.0.fixUpdate your import statements to use ESM `import` syntax (e.g., `import { AuthProvider } from 'react-oidc-context';`) and ensure your build configuration supports ESM.
Warnings
- breaking Version 3.0.0 introduced a breaking change by upgrading its peer dependency `oidc-client-ts` to v3.x. This change requires Node.js version >=18 and uses `crypto.subtle` instead of `crypto-js` for cryptographic operations.
- gotcha Since v3.0.0, the library relies on the Web Cryptography API (`crypto.subtle`), which is only available in secure contexts (HTTPS). Running your application over plain HTTP will cause runtime errors related to undefined `crypto.subtle`.
- gotcha It is crucial to implement the `onSigninCallback` function within your `oidcConfig` to clear the OIDC payload from the URL upon successful login. Failure to do so will prevent `signinSilent` (automatic token renewal) from working correctly after a page refresh.
- breaking The library transitioned to being an ESM-only module since v3.0.0. Direct `require()` statements for `react-oidc-context` will fail.
Install
-
npm install react-oidc-context -
yarn add react-oidc-context -
pnpm add react-oidc-context
Imports
- AuthProvider
const { AuthProvider } = require('react-oidc-context');import { AuthProvider } from 'react-oidc-context'; - useAuth
const { useAuth } = require('react-oidc-context');import { useAuth } from 'react-oidc-context'; - withAuthenticationRequired
const { withAuthenticationRequired } = require('react-oidc-context');import { withAuthenticationRequired } from 'react-oidc-context';
Quickstart
import React from 'react';
import ReactDOM from 'react-dom/client';
import { AuthProvider, useAuth } from 'react-oidc-context';
// Your OIDC configuration
const oidcConfig = {
authority: 'https://your-identity-provider.com',
client_id: 'your-client-id',
redirect_uri: window.location.origin + '/authentication/callback',
onSigninCallback: () => {
// IMPORTANT: Clear URL payload upon successful login to prevent issues with silent renew
window.history.replaceState({}, document.title, window.location.pathname);
},
// automaticSilentRenew: true, // Enable automatic token renewal
// scope: 'openid profile email',
// ... other oidc-client-ts UserManagerSettings
};
function App() {
const auth = useAuth();
switch (auth.activeNavigator) {
case 'signinSilent':
return <div>Signing you in silently...</div>;
case 'signoutRedirect':
return <div>Signing you out...</div>;
}
if (auth.isLoading) {
return <div>Loading authentication status...</div>;
}
if (auth.error) {
return <div>Authentication error: {auth.error.message}</div>;
}
if (auth.isAuthenticated) {
return (
<div>
Hello, {auth.user?.profile.name || auth.user?.profile.sub}{' '}
<button onClick={() => void auth.removeUser()}>Log out locally</button>
<button onClick={() => void auth.signoutRedirect()}>Log out from IdP</button>
</div>
);
}
return (
<div>
<p>You are not authenticated.</p>
<button onClick={() => void auth.signinRedirect()}>Log in</button>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<AuthProvider {...oidcConfig}>
<App />
</AuthProvider>
</React.StrictMode>
);