@axa-fr/react-oidc 7.29.3 → 7.29.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,749 +1,374 @@
1
1
  # @axa-fr/react-oidc
2
2
 
3
- [![Continuous Integration](https://github.com/AxaFrance/react-oidc/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/AxaFrance/react-oidc/actions/workflows/npm-publish.yml)
4
- [![npm downloads](https://img.shields.io/npm/dw/@axa-fr/react-oidc)](https://www.npmjs.com/package/@axa-fr/react-oidc)
3
+ React components and hooks for OpenID Connect (OIDC), built on [`@axa-fr/oidc-client`](../oidc-client/README.md). The provider handles browser authentication callbacks, session restoration, and token renewal; your components use hooks to sign in, read user information, and call protected APIs.
5
4
 
6
- **@axa-fr/oidc-client** the lightest and securest library to manage authentication with OpenID Connect (OIDC) and OAuth2 protocol. It is compatible with all OIDC providers.
7
- **@axa-fr/oidc-client** is a pure javascript library. It works with any JavaScript framework or library.
5
+ The library supports Authorization Code Flow with PKCE, multiple named configurations, optional service-worker token isolation, PAR, and DPoP. It is a browser-side authentication library, not a server-side session or authorization system.
8
6
 
9
- We provide a wrapper **@axa-fr/react-oidc** for **React** (compatible next.js) and we expect soon to provide one for **Vue**, **Angular** and **Svelte**.
7
+ - [Quick start](#quick-start)
8
+ - [Protect components](#protect-components)
9
+ - [Call protected APIs](#call-protected-apis)
10
+ - [User information and token hooks](#user-information-and-token-hooks)
11
+ - [Service worker](#service-worker)
12
+ - [Configuration, renewal, PAR, and DPoP](#configuration-renewal-par-and-dpop)
13
+ - [Custom components and provider options](#custom-components-and-provider-options)
14
+ - [Routing and Next.js](#routing-and-nextjs)
15
+ - [Named configurations](#named-configurations)
16
+ - [Errors and missing providers](#errors-and-missing-providers)
17
+ - [Examples and further reading](#examples-and-further-reading)
10
18
 
11
- - Try the React demo at https://black-rock-0dc6b0d03.1.azurestaticapps.net/ (most advanced)
12
- - Try the pure javascript demo at https://icy-glacier-004ab4303.2.azurestaticapps.net/
19
+ <a id="getting-started"></a>
13
20
 
14
- <img src="https://raw.githubusercontent.com/AxaFrance/oidc-client/main/docs/img/introduction.gif" alt="Sample React Oicd"/>
15
-
16
- - [About](#about)
17
- - [Getting Started](#getting-started)
18
- - [Run The Demo](#run-the-demo)
19
- - [Examples](#examples)
20
- - [How It Works](#how-it-works)
21
- - [NextJS](#NextJS)
22
- - [Hash route](#Hash-route)
23
- - [Service Worker Support](#service-worker-support)
24
-
25
- ## About
26
-
27
- @axa-fr/react is:
28
-
29
- - **Secure** :
30
- - With Demonstrating Proof of Possession (DPoP), your access_token and refresh_token are not usable outside your browser context (big protection)
31
- - With the use of Service Worker, your tokens (refresh_token and/or access_token) are not accessible to the JavaScript client code (if you follow good practices from [`FAQ`](https://github.com/AxaFrance/oidc-client/blob/main/FAQ.md) section)
32
- - OIDC using client side Code Credential Grant with pkce only
33
- - **Lightweight** : Unpacked Size on npm is **274 kB**
34
- - **Simple**
35
- - refresh_token and access_token are auto refreshed in background
36
- - with the use of the Service Worker, you do not need to inject the access_token in every fetch, you have only to configure OidcTrustedDomains.js file
37
- - **Multiple Authentication** :
38
- - You can authenticate many times to the same provider with different scope (for example you can acquire a new 'payment' scope for a payment)
39
- - You can authenticate to multiple different providers inside the same SPA (single page application) website
40
- - **Flexible** :
41
- - Work with Service Worker (more secure) and without for older browser (less secure).
42
- - You can disable Service Worker if you want (but less secure) and just use SessionStorage or LocalStorage mode.
43
-
44
- ![](https://github.com/AxaGuilDEv/react-oidc/blob/master/docs/img/schema_pcke_client_side_with_service_worker.png?raw=true)
45
-
46
- The service worker catch **access_token** and **refresh_token** that will never be accessible to the client.
47
-
48
- ## Getting Started
49
-
50
- ```sh
51
- npm install @axa-fr/react-oidc --save
52
-
53
- # To install or update OidcServiceWorker.js file, you can run
54
- node ./node_modules/@axa-fr/react-oidc/bin/copy-service-worker-files.mjs public
55
-
56
- # If you have a "public" folder, the 2 files will be created :
57
- # ./public/OidcServiceWorker.js <-- will be updated at each "npm install"
58
- # ./public/OidcTrustedDomains.js <-- won't be updated if already exist
59
- ```
60
-
61
- WARNING : If you use Service Worker mode, the OidcServiceWorker.js file should always be up to date with the version of the library. You may setup a postinstall script in your package.json file to update it at each npm install. For example :
21
+ ## Quick start
62
22
 
63
23
  ```sh
64
- "scripts": {
65
- ...
66
- "postinstall": "node ./node_modules/@axa-fr/react-oidc/bin/copy-service-worker-files.mjs public"
67
- },
24
+ npm install @axa-fr/react-oidc
68
25
  ```
69
26
 
70
- If you need a very secure mode where refresh_token and access_token will be hide behind a service worker that will proxify requests.
71
- The only file you should edit is "OidcTrustedDomains.js".
72
-
73
- ```javascript
74
- // OidcTrustedDomains.js
27
+ Register a public browser client with your identity provider using Authorization Code Flow with PKCE. Register the exact callback URL and post-logout URL, and allow the application's origin through CORS. Never embed a client secret in a browser application.
75
28
 
76
- // Add bellow trusted domains, access tokens will automatically injected to be send to
77
- // trusted domain can also be a path like https://www.myapi.com/users,
78
- // then all subroute like https://www.myapi.com/useers/1 will be authorized to send access_token to.
29
+ Replace the issuer and client ID below with your own settings. This example assumes a client-rendered React application with an HTML element named `root`. Your web server must serve the application on `/authentication/callback` as well as `/`.
79
30
 
80
- // Domains used by OIDC server must be also declared here
81
- const trustedDomains = {
82
- default: {
83
- oidcDomains: ['https://demo.duendesoftware.com'],
84
- accessTokenDomains: ['https://www.myapi.com/users'],
85
- },
86
- };
87
-
88
- // Service worker will continue to give access token to the JavaScript client
89
- // Ideal to hide refresh token from client JavaScript, but to retrieve access_token for some
90
- // scenarios which require it. For example, to send it via websocket connection.
91
- trustedDomains.config_show_access_token = {
92
- oidcDomains: ['https://demo.duendesoftware.com'],
93
- accessTokenDomains: ['https://www.myapi.com/users'],
94
- showAccessToken: true,
95
- // convertAllRequestsToCorsExceptNavigate: false, // default value is false
96
- // setAccessTokenToNavigateRequests: true, // default value is true
97
- // bypassAllNonOidcRequests: false, // default value is false; when true, requests outside OIDC and accessTokenDomains are handled by the browser
98
- };
99
-
100
- // DPoP (Demonstrating Proof of Possession) will be activated for the following domains
101
- trustedDomains.config_with_dpop = {
102
- domains: ['https://demo.duendesoftware.com'],
103
- demonstratingProofOfPossession: true,
104
- demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: true, // default value is false, inject DPOP token only when DPOP header is present
105
- // Optional, more details bellow
106
- /*demonstratingProofOfPossessionConfiguration: {
107
- importKeyAlgorithm: {
108
- name: 'ECDSA',
109
- namedCurve: 'P-256',
110
- hash: {name: 'ES256'}
111
- },
112
- signAlgorithm: {name: 'ECDSA', hash: {name: 'SHA-256'}},
113
- generateKeyAlgorithm: {
114
- name: 'ECDSA',
115
- namedCurve: 'P-256'
116
- },
117
- digestAlgorithm: { name: 'SHA-256' },
118
- jwtHeaderAlgorithm : 'ES256'
119
- }*/
120
- };
31
+ ```tsx
32
+ import { useState } from 'react';
33
+ import { createRoot } from 'react-dom/client';
34
+ import { OidcProvider, useOidc, type OidcConfiguration } from '@axa-fr/react-oidc';
121
35
 
122
- // Setting allowMultiTabLogin to true will enable storing login-specific parameters (state, nonce, code verifier)
123
- // separately for each tab. This will prevent errors when logins are initiated from multiple tabs.
124
- // IMPORTANT: When allowMultiTabLogin is true, you MUST use the OIDC fetch provided by useOidcFetch()
125
- // or withOidcFetch() for API requests. The service worker embeds a tab-specific token placeholder
126
- // in the Authorization header, which it then replaces with the real access token.
127
- // Using a plain fetch or axios without the OIDC fetch wrapper will result in requests being sent
128
- // without an Authorization header (401 errors), because the service worker cannot determine which
129
- // tab's token to inject without the placeholder.
130
- // Example with axios: configure it to use the OIDC fetch as its adapter or use the OIDC fetch directly.
131
- trustedDomains.config_multi_tab_login = {
132
- domains: ['https://demo.duendesoftware.com'],
133
- allowMultiTabLogin: true,
36
+ const configuration: OidcConfiguration = {
37
+ client_id: 'your-public-client',
38
+ authority: 'https://issuer.example.com',
39
+ redirect_uri: `${window.location.origin}/authentication/callback`,
40
+ scope: 'openid profile',
134
41
  };
135
- ```
136
-
137
- ## Run The Demo
138
42
 
139
- ```sh
140
- git clone https://github.com/AxaFrance/oidc-client.git
141
- cd oidc-client
142
- pnpm install
143
- cd /examples/react-oidc-demo
144
- pnpm install
145
- pnpm start
146
- # then navigate to http://localhost:4200
147
- ```
148
-
149
- ## Examples
150
-
151
- ### Application startup
152
-
153
- The library is router agnostic and will use native History API.
43
+ function Account(): React.JSX.Element {
44
+ const { login, logout, isAuthenticated } = useOidc();
45
+ const [hasError, setHasError] = useState(false);
46
+
47
+ const changeSession = async (): Promise<void> => {
48
+ setHasError(false);
49
+ try {
50
+ if (isAuthenticated) {
51
+ await logout('/');
52
+ } else {
53
+ await login('/');
54
+ }
55
+ } catch {
56
+ setHasError(true);
57
+ }
58
+ };
154
59
 
155
- The default routes used internally :
60
+ return (
61
+ <main>
62
+ <p>{isAuthenticated ? 'Signed in' : 'Not signed in'}</p>
63
+ <button type="button" onClick={changeSession}>
64
+ {isAuthenticated ? 'Sign out' : 'Sign in'}
65
+ </button>
66
+ {hasError && <p role="alert">Authentication failed. Please try again.</p>}
67
+ </main>
68
+ );
69
+ }
156
70
 
157
- - www.your-app.fr/authentication/callback
71
+ const root = document.getElementById('root');
72
+ if (!root) throw new Error('Missing root element');
158
73
 
159
- ```javascript
160
- import React from 'react';
161
- import { render } from 'react-dom';
162
- import { BrowserRouter as Router } from 'react-router-dom';
163
- import { OidcProvider } from '@axa-fr/react-oidc';
164
- import Header from './Layout/Header';
165
- import Routes from './Router';
166
-
167
- // This configuration use hybrid mode
168
- // ServiceWorker are used if available (more secure) else tokens are given to the client
169
- // You need to give inside your code the "access_token" when using fetch
170
- const configuration = {
171
- client_id: 'interactive.public.short',
172
- redirect_uri: window.location.origin + '/authentication/callback',
173
- silent_redirect_uri: window.location.origin + '/authentication/silent-callback',
174
- scope: 'openid profile email api offline_access', // offline_access scope allow your client to retrieve the refresh_token
175
- authority: 'https://demo.duendesoftware.com',
176
- par: 'auto',
177
- service_worker_relative_url: '/OidcServiceWorker.js', // just comment that line to disable service worker mode
178
- service_worker_only: false,
179
- demonstrating_proof_of_possession: false,
180
- };
181
-
182
- const App = () => (
74
+ createRoot(root).render(
183
75
  <OidcProvider configuration={configuration}>
184
- <Router>
185
- <Header />
186
- <Routes />
187
- </Router>
188
- </OidcProvider>
76
+ <Account />
77
+ </OidcProvider>,
189
78
  );
190
-
191
- render(<App />, document.getElementById('root'));
192
79
  ```
193
80
 
194
- > [!WARNING]
195
- > If you have both `redirect_uri` and `silent_redirect_uri` configured, their value must be different.
196
-
197
- ```javascript
198
- const configuration = {
199
- loadingComponent: ReactComponent, // you can inject your own loading component
200
- sessionLostComponent: ReactComponent, // you can inject your own session lost component
201
- authenticating: ReactComponent, // you can inject your own authenticating component
202
- authenticatingErrorComponent: ReactComponent,
203
- callbackSuccessComponent: ReactComponent, // you can inject your own call back success component
204
- serviceWorkerNotSupportedComponent: ReactComponent, // you can inject your page that explains you require a more modern browser
205
- onSessionLost: Function, // If set, "sessionLostComponent" is not displayed, and onSessionLost callback is called instead
206
- configuration: {
207
- client_id: String.isRequired, // oidc client id
208
- redirect_uri: String.isRequired, // oidc redirect url
209
- silent_redirect_uri: String, // Optional activate silent-signin that use cookies between OIDC server and client javascript to restore sessions
210
- silent_login_uri: String, // Optional, route that triggers the signin
211
- silent_login_timeout: Number, // Optional, default is 12000 milliseconds
212
- scope: String.isRequired, // oidc scope (you need to set "offline_access")
213
- authority: String.isRequired,
214
- storage: Storage, // Default sessionStorage, you can set localStorage, but it is not secure
215
- login_state_storage: Storage, // Optional. Storage used only for authorization flow state (state, code_verifier, nonce, login params). Defaults to the value of `storage`. Set to sessionStorage when using storage: localStorage to prevent race conditions when multiple tabs start the login flow simultaneously.
216
- authority_configuration: {
217
- // Optional for providers that do not implement OIDC server auto-discovery via a .wellknown URL
218
- authorization_endpoint: String,
219
- token_endpoint: String,
220
- userinfo_endpoint: String,
221
- end_session_endpoint: String,
222
- revocation_endpoint: String,
223
- pushed_authorization_request_endpoint: String,
224
- require_pushed_authorization_requests: Boolean,
225
- check_session_iframe: String,
226
- issuer: String,
227
- },
228
- refresh_time_before_tokens_expiration_in_second: Number, // default is 120 seconds
229
- service_worker_relative_url: String,
230
- service_worker_keep_alive_path: String, // default is "/"
231
- service_worker_only: Boolean, // default false
232
- service_worker_activate: () => boolean, // you can take the control of the service worker default activation which use user agent string
233
- service_worker_register: (url: string) => Promise<ServiceWorkerRegistration>, // Optional, you can take the control of the service worker registration
234
- extras: StringMap | undefined, // ex: {'prompt': 'consent', 'access_type': 'offline'} list of key/value that is sent to the OIDC server (more info: https://github.com/openid/AppAuth-JS)
235
- token_request_extras: StringMap | undefined, // ex: {'prompt': 'consent', 'access_type': 'offline'} list of key/value that is sent to the OIDC server during token request (more info: https://github.com/openid/AppAuth-JS)
236
- withCustomHistory: Function, // Override history modification, return an instance with replaceState(url, stateHistory) implemented (like History.replaceState())
237
- authority_time_cache_wellknowurl_in_second: 60 * 60, // Time to cache in seconds of the openid well-known URL, default is 1 hour
238
- authority_timeout_wellknowurl_in_millisecond: 10000, // Timeout in milliseconds of the openid well-known URL, default is 10 seconds, then an error is thrown
239
- par: 'disabled' | 'auto' | 'required', // Pushed Authorization Requests mode, default is 'disabled'
240
- par_request_timeout: Number, // PAR endpoint timeout in milliseconds, default is 10000
241
- monitor_session: Boolean, // Add OpenID monitor session, default is false (more information https://openid.net/specs/openid-connect-session-1_0.html), if you need to set it to true consider https://infi.nl/nieuws/spa-necromancy/
242
- onLogoutFromAnotherTab: Function, // Optional, can be set to override the default behavior, this function is triggered when a user with the same subject is logged out from another tab when session_monitor is active
243
- onLogoutFromSameTab: Function, // Optional, can be set to override the default behavior, this function is triggered when a user is logged out from the same tab when session_monitor is active
244
- token_renew_mode: String, // Optional, update tokens based on the selected token(s) lifetime: "access_token_or_id_token_invalid" (default), "access_token_invalid", "id_token_invalid"
245
- token_automatic_renew_mode: TokenAutomaticRenewMode.AutomaticOnlyWhenFetchExecuted, // Optional, default is TokenAutomaticRenewMode.AutomaticBeforeTokensExpiration
246
- // TokenAutomaticRenewMode.AutomaticBeforeTokensExpiration: renew tokens automatically before they expire
247
- // TokenAutomaticRenewMode.AutomaticOnlyWhenFetchExecuted: renew tokens automatically only when fetch is executed
248
- // It requires you to use fetch given by hook useOidcFetch(fetch) or HOC withOidcFetch(fetch)(Component)
249
- logout_tokens_to_invalidate: Array<string>, // Optional tokens to invalidate during logout, default: ['access_token', 'refresh_token']
250
- location: ILOidcLocation, // Optional, default is window.location, you can inject your own location object respecting the ILOidcLocation interface
251
- demonstrating_proof_of_possession: Boolean, // Optional, default is false, if true, the the Demonstrating Proof of Possession will be activated //https://www.rfc-editor.org/rfc/rfc9449.html#name-protected-resource-access
252
- demonstrating_proof_of_possession_configuration: DemonstratingProofOfPossessionConfiguration // Optional, more details bellow
253
- },
254
- };
255
-
256
- demonstrating_proof_of_possession_configuration: DemonstratingProofOfPossessionConfiguration // Optional, more details bellow
257
- };
258
-
259
- interface DemonstratingProofOfPossessionConfiguration
260
- {
261
- generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams,
262
- digestAlgorithm: AlgorithmIdentifier,
263
- importKeyAlgorithm: AlgorithmIdentifier | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | AesKeyAlgorithm,
264
- signAlgorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams,
265
- jwtHeaderAlgorithm: string
266
- };
267
-
268
- // default value of demonstrating_proof_of_possession_configuration
269
- const defaultDemonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration ={
270
- importKeyAlgorithm: {
271
- name: 'ECDSA',
272
- namedCurve: 'P-256',
273
- hash: {name: 'ES256'}
274
- },
275
- signAlgorithm: {name: 'ECDSA', hash: {name: 'SHA-256'}},
276
- generateKeyAlgorithm: {
277
- name: 'ECDSA',
278
- namedCurve: 'P-256'
279
- },
280
- digestAlgorithm: { name: 'SHA-256' },
281
- jwtHeaderAlgorithm : 'ES256'
282
- };
81
+ `OidcProvider` processes the callback route; do not call `loginCallbackAsync()` yourself inside this React setup. `login('/')` selects the application destination after authentication, not the registered callback URL.
283
82
 
83
+ This example uses browser storage. For optional token isolation, follow the [service-worker setup](#service-worker).
284
84
 
85
+ ```mermaid
86
+ flowchart LR
87
+ UI["React components and hooks"] --> Provider["OidcProvider"]
88
+ Provider --> Client["@axa-fr/oidc-client"]
89
+ Client --> IdP["OIDC identity provider"]
90
+ Client --> SW["Optional service worker"]
91
+ SW --> API["Trusted API"]
92
+ Client --> Fetch["OIDC fetch without worker"]
93
+ Fetch --> API
285
94
  ```
286
95
 
287
- ### Pushed Authorization Requests (PAR)
96
+ ## Protect components
288
97
 
289
- PAR is configured on the nested OIDC `configuration` object:
98
+ `OidcSecure` starts login when there is no authenticated session and renders its children only after authentication:
290
99
 
291
100
  ```tsx
292
- const configuration = {
293
- client_id: 'spa-client',
294
- redirect_uri: `${window.location.origin}/authentication/callback`,
295
- scope: 'openid profile',
296
- authority: 'https://issuer.example.com',
297
- par: 'auto', // 'disabled' (default), 'auto', or 'required'
298
- };
299
- ```
300
-
301
- `auto` uses the discovered `pushed_authorization_request_endpoint` when it is
302
- available. `required` fails before navigation if no endpoint is available.
303
- Once PAR is selected, a PAR endpoint error is surfaced and never silently
304
- downgraded. Browser deployments require the issuer's PAR endpoint to allow
305
- CORS from the application origin. See the
306
- [`@axa-fr/oidc-client` PAR documentation](../oidc-client/README.md#pushed-authorization-requests-par)
307
- for complete mode semantics, custom authority metadata, error handling, and
308
- security guidance.
309
-
310
- ## How to consume
311
-
312
- > **Note (issue #1679):** `useOidc`, `useOidcUser`, `useOidcAccessToken` and
313
- > `useOidcIdToken` are safe to call **outside** of an `<OidcProvider>` (e.g.
314
- > in unit tests or Storybook stories). When no provider is mounted, they
315
- > emit a single `console.warn` per configuration name and return stable
316
- > default values (`isAuthenticated: false`, `oidcUser: null`,
317
- > `accessToken: null`, `idToken: null`, with no-op `login`/`logout`/
318
- > `renewTokens`/`reloadOidcUser`). Use `OidcClient.getOrThrow(name)` if you
319
- > prefer the previous fail-fast behaviour.
320
-
321
- "useOidc" returns all props from the Hook :
322
-
323
- ```javascript
324
- import React from 'react';
325
- import { useOidc } from './oidc';
326
-
327
- export const Home = () => {
328
- const { login, logout, renewTokens, isAuthenticated } = useOidc();
101
+ import { OidcSecure } from '@axa-fr/react-oidc';
329
102
 
103
+ export function PrivatePage(): React.JSX.Element {
330
104
  return (
331
- <div className="container-fluid mt-3">
332
- <div className="card">
333
- <div className="card-body">
334
- <h5 className="card-title">Welcome !!!</h5>
335
- <p className="card-text">React Demo Application protected by OpenId Connect</p>
336
- {!isAuthenticated && (
337
- <button type="button" className="btn btn-primary" onClick={() => login('/profile')}>
338
- Login
339
- </button>
340
- )}
341
- {isAuthenticated && (
342
- <button type="button" className="btn btn-primary" onClick={() => logout()}>
343
- logout
344
- </button>
345
- )}
346
- {isAuthenticated && (
347
- <button type="button" className="btn btn-primary" onClick={() => renewTokens()}>
348
- renewTokens
349
- </button>
350
- )}
351
- </div>
352
- </div>
353
- </div>
105
+ <OidcSecure callbackPath="/account">
106
+ <h1>Account</h1>
107
+ </OidcSecure>
354
108
  );
355
- };
109
+ }
356
110
  ```
357
111
 
358
- The Hook method exposes :
359
-
360
- - isAuthenticated : if the user is logged in or not
361
- - logout: logout function (return a promise)
362
- - login: login function 'return a promise'
363
- - renewTokens: renew tokens function 'return a promise'
364
-
365
- ## How to secure a component
112
+ Place it beneath `OidcProvider`. You can protect the whole application, a route element, or a smaller component. Optional props are `callbackPath`, authorization `extras`, and `configurationName`.
366
113
 
367
- `OidcSecure` component trigger authentication in case user is not authenticated. So, the children of that component can be accessible only once you are connected.
114
+ The higher-order component (HOC) equivalent is:
368
115
 
369
- ```javascript
370
- import React from 'react';
371
- import { OidcSecure } from '@axa-fr/react-oidc';
116
+ ```tsx
117
+ import { withOidcSecure } from '@axa-fr/react-oidc';
372
118
 
373
- const AdminSecure = () => (
374
- <OidcSecure>
375
- <h1>My sub component</h1>
376
- </OidcSecure>
377
- );
119
+ function AccountDetails(): React.JSX.Element {
120
+ return <h1>Account details</h1>;
121
+ }
378
122
 
379
- // adding the oidc user in the props
380
- export default AdminSecure;
123
+ export const ProtectedAccountDetails = withOidcSecure(AccountDetails, '/account');
381
124
  ```
382
125
 
383
- ## How to secure a component: HOC method
384
-
385
- `withOidcSecure` will act the same as `OidcSecure`,it will also trigger authentication in case the user is not authenticated.
386
-
387
- ```javascript
388
- import React from 'react';
389
- import { Switch, Route } from 'react-router-dom';
390
- import { withOidcSecure } from '@axa-fr/react-oidc';
391
- import Home from '../Pages/Home';
392
- import Dashboard from '../Pages/Dashboard';
393
- import Admin from '../Pages/Admin';
394
-
395
- const Routes = () => (
396
- <Switch>
397
- <Route exact path="/" component={Home} />
398
- <Route path="/dashboard" component={withOidcSecure(Dashboard)} />
399
- <Route path="/admin" component={Admin} />
400
- <Route path="/home" component={Home} />
401
- </Switch>
402
- );
126
+ Its signature is `withOidcSecure(Component, callbackPath?, extras?, configurationName?)`.
403
127
 
404
- export default Routes;
405
- ```
128
+ These components gate the UI; your APIs must independently validate tokens and enforce authorization.
406
129
 
407
- ## How to get "Access Token": Hook method
130
+ ## Call protected APIs
408
131
 
409
- ```javascript
410
- import { useOidcAccessToken } from '@axa-fr/react-oidc';
132
+ `useOidcFetch()` returns a fetch wrapper that attaches the access token (or a service-worker placeholder) and integrates with renewal. Use it only for trusted API URLs, not arbitrary user-supplied destinations.
411
133
 
412
- const DisplayAccessToken = () => {
413
- const { accessToken, accessTokenPayload } = useOidcAccessToken();
134
+ ```tsx
135
+ import { useState } from 'react';
136
+ import { useOidcFetch } from '@axa-fr/react-oidc';
137
+
138
+ export function ProfileRequest(): React.JSX.Element {
139
+ const { fetch: oidcFetch } = useOidcFetch();
140
+ const [status, setStatus] = useState('Ready');
141
+
142
+ const loadProfile = async (): Promise<void> => {
143
+ setStatus('Loading…');
144
+ try {
145
+ const response = await oidcFetch('https://api.example.com/profile');
146
+ if (!response.ok) {
147
+ throw new Error(`API request failed with status ${response.status}`);
148
+ }
149
+ setStatus('Profile request succeeded');
150
+ } catch {
151
+ setStatus('Could not load the profile');
152
+ }
153
+ };
414
154
 
415
- if (!accessToken) {
416
- return <p>you are not authentified</p>;
417
- }
418
155
  return (
419
- <div className="card text-white bg-info mb-3">
420
- <div className="card-body">
421
- <h5 className="card-title">Access Token</h5>
422
- <p style={{ color: 'red', backgroundColor: 'white' }}>
423
- Please consider to configure the ServiceWorker in order to protect your application from
424
- XSRF attacks. ""access_token" and "refresh_token" will never be accessible from your
425
- client side javascript.
426
- </p>
427
- {<p className="card-text">{JSON.stringify(accessToken)}</p>}
428
- {accessTokenPayload != null && (
429
- <p className="card-text">{JSON.stringify(accessTokenPayload)}</p>
430
- )}
431
- </div>
432
- </div>
156
+ <>
157
+ <button type="button" onClick={loadProfile}>
158
+ Load profile
159
+ </button>
160
+ <p role="status">{status}</p>
161
+ </>
433
162
  );
434
- };
163
+ }
435
164
  ```
436
165
 
437
- ## How to get IDToken: Hook method
166
+ Render protected API consumers beneath `OidcSecure`, or wait until `useOidc().isAuthenticated` is true. Check `response.ok`: ordinary HTTP error responses do not automatically reject.
438
167
 
439
- ```javascript
440
- import { useOidcIdToken } from '@axa-fr/react-oidc';
168
+ | API | Arguments / result |
169
+ | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
170
+ | `useOidcFetch(fetch?, configurationName?, demonstratingProofOfPossession?)` | Returns `{ fetch }`; defaults to browser fetch and configuration `'default'`. |
171
+ | `withOidcFetch(fetch?, configurationName?, demonstratingProofOfPossession?)(Component)` | Injects a `fetch` prop into a component. |
441
172
 
442
- const DisplayIdToken = () => {
443
- const { idToken, idTokenPayload } = useOidcIdToken();
173
+ For example, `withOidcFetch()(ProfileComponent)` supplies the same wrapper through props instead of a hook.
444
174
 
445
- if (!idToken) {
446
- return <p>you are not authentified</p>;
447
- }
175
+ ## User information and token hooks
448
176
 
449
- return (
450
- <div className="card text-white bg-info mb-3">
451
- <div className="card-body">
452
- <h5 className="card-title">ID Token</h5>
453
- {<p className="card-text">{JSON.stringify(idToken)}</p>}
454
- {idTokenPayload != null && <p className="card-text">{JSON.stringify(idTokenPayload)}</p>}
455
- </div>
456
- </div>
457
- );
458
- };
459
- ```
177
+ ### User information
460
178
 
461
- ## How to get User Information: Hook method
179
+ `useOidcUser()` reads the provider's user-info endpoint and exposes loading state. The exported enum is **`OidcUserStatus`**:
462
180
 
463
- ```javascript
464
- import { useOidcUser, UserStatus } from '@axa-fr/react-oidc';
181
+ ```tsx
182
+ import { OidcUserStatus, useOidcUser } from '@axa-fr/react-oidc';
465
183
 
466
- const DisplayUserInfo = () => {
184
+ export function UserGreeting(): React.JSX.Element {
467
185
  const { oidcUser, oidcUserLoadingState } = useOidcUser();
468
186
 
469
187
  switch (oidcUserLoadingState) {
470
- case UserStatus.Loading:
471
- return <p>User Information are loading</p>;
472
- case UserStatus.Unauthenticated:
473
- return <p>you are not authenticated</p>;
474
- case UserStatus.LoadingError:
475
- return <p>Fail to load user information</p>;
188
+ case OidcUserStatus.Loading:
189
+ return <p>Loading profile…</p>;
190
+ case OidcUserStatus.Unauthenticated:
191
+ return <p>Please sign in.</p>;
192
+ case OidcUserStatus.LoadingError:
193
+ return <p>Could not load your profile.</p>;
476
194
  default:
477
- return (
478
- <div className="card text-white bg-success mb-3">
479
- <div className="card-body">
480
- <h5 className="card-title">User information</h5>
481
- <p className="card-text">{JSON.stringify(oidcUser)}</p>
482
- </div>
483
- </div>
484
- );
195
+ return <p>Hello, {oidcUser?.name ?? 'there'}.</p>;
485
196
  }
486
- };
197
+ }
487
198
  ```
488
199
 
489
- ## How to get a fetch that inject Access_Token: Hook method
200
+ The hook also returns `reloadOidcUser()`. Use `useOidcUser<MyUserInfo>(configurationName?, demonstratingProofOfPossession?)` for custom claims, where `MyUserInfo` extends `OidcUserInfo`.
490
201
 
491
- If you are not using the service worker. The Fetch function needs to send AccessToken.
492
- This hook will give you a wrapped fetch that adds the access token for you.
202
+ ### Hook reference
493
203
 
494
- ```javascript
495
- import React, { useEffect, useState } from 'react';
496
- import { useOidcFetch, OidcSecure } from '@axa-fr/react-oidc';
204
+ | Hook | Return values |
205
+ | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
206
+ | `useOidc(configurationName?)` | `isAuthenticated`, `login`, `logout`, `renewTokens`. |
207
+ | `useOidcUser<T>(configurationName?, demonstratingProofOfPossession?)` | `oidcUser`, `oidcUserLoadingState`, `reloadOidcUser`. |
208
+ | `useOidcAccessToken(configurationName?)` | `accessToken`, `accessTokenPayload`, and, when enabled, `generateDemonstrationOfProofOfPossessionAsync`. |
209
+ | `useOidcIdToken(configurationName?)` | `idToken`, `idTokenPayload`. |
497
210
 
498
- const DisplayUserInfo = ({ fetch }) => {
499
- const [oidcUser, setOidcUser] = useState(null);
500
- const [isLoading, setLoading] = useState(true);
211
+ `login(callbackPath?, extras?, silentLoginOnly?, scope?)`, `logout(callbackPath?, extras?)`, and `renewTokens(extras?)` return promises.
501
212
 
502
- useEffect(() => {
503
- const fetchUserInfoAsync = async () => {
504
- const res = await fetch('https://demo.duendesoftware.com/connect/userinfo');
505
- if (res.status != 200) {
506
- return null;
507
- }
508
- return res.json();
509
- };
510
- let isMounted = true;
511
- fetchUserInfoAsync().then(userInfo => {
512
- if (isMounted) {
513
- setLoading(false);
514
- setOidcUser(userInfo);
515
- }
516
- });
517
- return () => {
518
- isMounted = false;
519
- };
520
- }, []);
521
-
522
- if (isLoading) {
523
- return <>Loading</>;
524
- }
213
+ Prefer `useOidcFetch` over manually building authorization headers. When worker token hiding is enabled, `accessToken` is a placeholder rather than the real token. Do not render or log raw tokens, and treat user claims as personal data. An ID token identifies the user to the client; it is not a replacement for an API access token.
525
214
 
526
- return (
527
- <div className="container mt-3">
528
- <div className="card text-white bg-success mb-3">
529
- <div className="card-body">
530
- <h5 className="card-title">User information</h5>
531
- {oidcUser != null && <p className="card-text">{JSON.stringify(oidcUser)}</p>}
532
- </div>
533
- </div>
534
- </div>
535
- );
536
- };
215
+ ## Service worker
537
216
 
538
- export const FetchUserHook = () => {
539
- const { fetch } = useOidcFetch();
540
- return (
541
- <OidcSecure>
542
- <DisplayUserInfo fetch={fetch} />
543
- </OidcSecure>
544
- );
545
- };
217
+ Ensure your application's static-assets directory exists (`public` below), then install the worker assets:
218
+
219
+ ```sh
220
+ node ./node_modules/@axa-fr/react-oidc/bin/copy-service-worker-files.mjs public
546
221
  ```
547
222
 
548
- ## How to get a fetch that inject Access_Token : HOC method
223
+ Keep the generated `OidcServiceWorker.js` synchronized with package updates. For example, merge this into your application's `package.json`:
549
224
 
550
- If your are not using the service worker. Fetch function need to send AccessToken.
551
- This HOC give you a wrapped fetch that add the access token for you.
225
+ ```json
226
+ {
227
+ "scripts": {
228
+ "postinstall": "node ./node_modules/@axa-fr/react-oidc/bin/copy-service-worker-files.mjs public"
229
+ }
230
+ }
231
+ ```
552
232
 
553
- ```javascript
554
- import React, { useEffect, useState } from 'react';
555
- import { useOidcFetch, OidcSecure } from '@axa-fr/react-oidc';
233
+ Then:
556
234
 
557
- const DisplayUserInfo = ({ fetch }) => {
558
- const [oidcUser, setOidcUser] = useState(null);
559
- const [isLoading, setLoading] = useState(true);
235
+ 1. Configure `public/OidcTrustedDomains.js` with your provider and API destinations.
236
+ 2. Add `service_worker_relative_url: '/OidcServiceWorker.js'` to the OIDC configuration.
237
+ 3. Set `service_worker_only: true` if login must not fall back to browser token storage.
238
+ 4. Serve the worker over HTTPS (or localhost) with a scope that covers the application.
560
239
 
561
- useEffect(() => {
562
- const fetchUserInfoAsync = async () => {
563
- const res = await fetch('https://demo.duendesoftware.com/connect/userinfo');
564
- if (res.status != 200) {
565
- return null;
566
- }
567
- return res.json();
568
- };
569
- let isMounted = true;
570
- fetchUserInfoAsync().then(userInfo => {
571
- if (isMounted) {
572
- setLoading(false);
573
- setOidcUser(userInfo);
574
- }
575
- });
576
- return () => {
577
- isMounted = false;
578
- };
579
- }, []);
580
-
581
- if (isLoading) {
582
- return <>Loading</>;
583
- }
240
+ Follow the [core service-worker guide](../oidc-client/README.md#service-worker) for a trusted-domain example, all options, token-exposure choices, and fallback behavior.
584
241
 
585
- return (
586
- <div className="container mt-3">
587
- <div className="card text-white bg-success mb-3">
588
- <div className="card-body">
589
- <h5 className="card-title">User information</h5>
590
- {oidcUser != null && <p className="card-text">{JSON.stringify(oidcUser)}</p>}
591
- </div>
592
- </div>
593
- </div>
594
- );
595
- };
242
+ **Multi-tab login:** when `allowMultiTabLogin: true` is set in a trusted-domain entry, use `useOidcFetch()` or `withOidcFetch()` for protected API calls. Their tab-specific placeholder identifies the session to the worker. Plain fetch or a default Axios request cannot supply that marker and may result in HTTP 401.
596
243
 
597
- const UserInfoWithFetchHoc = withOidcFetch(fetch)(DisplayUserInfo);
598
- export const FetchUserHoc = () => (
599
- <OidcSecure>
600
- <UserInfoWithFetchHoc />
601
- </OidcSecure>
602
- );
603
- ```
244
+ The worker can hide access and refresh tokens from application JavaScript, but it does **not** prevent XSS or stop injected code from making requests through your application. It does not hide all identity information. Keep normal XSS defenses and avoid broad trusted-domain rules.
604
245
 
605
- ## Components override
246
+ ## Configuration, renewal, PAR, and DPoP
606
247
 
607
- You can inject your own components.
608
- All components definition receive props `configurationName`. Please checkout the demo for more complete example.
248
+ `OidcProvider` accepts the same `OidcConfiguration` as the vanilla client. Keep provider props, such as custom components and routing callbacks, outside that configuration object.
609
249
 
610
- ```javascript
611
- import React from 'react';
612
- import { render } from 'react-dom';
613
- import { BrowserRouter as Router } from 'react-router-dom';
614
- import { OidcProvider } from '@axa-fr/react-oidc';
615
- import Header from './Layout/Header';
616
- import Routes from './Router';
617
-
618
- // This configuration use hybrid mode
619
- // ServiceWorker are used if available (more secure) else tokens are given to the client
620
- // You need to give inside your code the "access_token" when using fetch
621
- const configuration = {
622
- client_id: 'interactive.public.short',
623
- redirect_uri: 'http://localhost:4200/authentication/callback',
624
- silent_redirect_uri: 'http://localhost:4200/authentication/silent-callback',
625
- scope: 'openid profile email api offline_access',
626
- authority: 'https://demo.identityserver.io',
627
- service_worker_relative_url: '/OidcServiceWorker.js',
628
- service_worker_only: false,
629
- };
250
+ - **Configuration:** see the [core configuration reference](../oidc-client/README.md#configuration) for required fields, storage, discovery, timeouts, logout, and session monitoring.
251
+ - **Renewal:** automatic renewal is enabled by default. For `TokenAutomaticRenewMode.AutomaticOnlyWhenFetchExecuted`, use `useOidcFetch`/`withOidcFetch` so requests trigger renewal. See [renewal behavior and strict renewal](../oidc-client/README.md#token-renewal).
252
+ - **Silent login:** add a distinct `silent_redirect_uri` if required. The provider handles its silent-login routes. Provider and browser cookie policies can prevent iframe login.
253
+ - **PAR:** set `par: 'auto'` or `'required'` in `configuration`; the default is `'disabled'`. `auto` uses PAR when an endpoint is advertised; missing required endpoints fail before navigation. Once selected, PAR errors never silently downgrade. See [full PAR semantics, errors, and CORS requirements](../oidc-client/README.md#pushed-authorization-requests-par).
254
+ - **DPoP:** enable `demonstrating_proof_of_possession` and use `useOidcFetch(undefined, 'default', true)` or `withOidcFetch(undefined, 'default', true)`. For user info, use `useOidcUser('default', true)`. See [DPoP and worker-specific settings](../oidc-client/README.md#dpop). Both the identity provider and resource server must support it.
630
255
 
631
- const Loading = () => <p>Loading</p>;
632
- const AuthenticatingError = () => <p>Authenticating error</p>;
633
- const Authenticating = () => <p>Authenticating</p>;
634
- const SessionLost = () => <p>Session Lost</p>;
635
- const ServiceWorkerNotSupported = () => <p>Not supported</p>;
636
- const CallBackSuccess = () => <p>Success</p>;
637
-
638
- //const [isSessionLost, setIsSessionLost] = useState(false);
639
-
640
- //const onSessionLost = ()=>{
641
- // setIsSessionLost(true);
642
- //}
643
-
644
- const App = () => (
645
- <OidcProvider
646
- configuration={configuration}
647
- loadingComponent={Loading}
648
- authenticatingErrorComponent={AuthenticatingError}
649
- authenticatingComponent={Authenticating}
650
- sessionLostComponent={SessionLost}
651
- //onSessionLost={onSessionLost} // If set "sessionLostComponent" is not displayed and onSessionLost callback is called instead
652
- serviceWorkerNotSupportedComponent={ServiceWorkerNotSupported}
653
- callbackSuccessComponent={CallBackSuccess}
654
- >
655
- {/* isSessionLost && <SessionLost />*/}
656
- <Router>
657
- <Header />
658
- <Routes />
659
- </Router>
660
- </OidcProvider>
256
+ ## Custom components and provider options
257
+
258
+ Replace built-in status screens with your own components. These are **provider props**, not fields inside `configuration`:
259
+
260
+ ```tsx
261
+ const Loading = (): React.JSX.Element => <p>Restoring your session…</p>;
262
+ const AuthenticationError = (): React.JSX.Element => (
263
+ <p role="alert">Sign-in failed. Please return to the sign-in page and try again.</p>
661
264
  );
662
265
 
663
- render(<App />, document.getElementById('root'));
266
+ <OidcProvider
267
+ configuration={configuration}
268
+ loadingComponent={Loading}
269
+ authenticatingErrorComponent={AuthenticationError}
270
+ >
271
+ <App />
272
+ </OidcProvider>;
664
273
  ```
665
274
 
666
- ## How It Works
275
+ | Provider prop | Purpose |
276
+ | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
277
+ | `configuration`, `configurationName` | Client configuration and its name (`'default'` by default). |
278
+ | `loadingComponent` | Session restoration/loading screen. |
279
+ | `loadingTimeoutComponent` | Screen shown when the loading watchdog expires. |
280
+ | `authenticatingComponent` | Screen shown while starting login. |
281
+ | `authenticatingErrorComponent` | Login or callback failure screen. |
282
+ | `callbackSuccessComponent` | Screen shown after a successful callback. |
283
+ | `sessionLostComponent` | Session-loss screen. |
284
+ | `serviceWorkerNotSupportedComponent` | Unavailable-worker screen when worker-only mode is required. |
285
+ | `onSessionLost` | Handles session loss instead of displaying the built-in session-loss flow. |
286
+ | `onLogoutFromAnotherTab`, `onLogoutFromSameTab` | React to logout events. |
287
+ | `onEvent(configurationName, eventName, data)` | Observe client events; avoid logging complete payloads. |
288
+ | `withCustomHistory` | Returns a history adapter with `replaceState(url, stateHistory?)`. |
289
+ | `navigateAfterCallback(callbackPath)` | Async callback to perform post-login navigation; takes precedence over the history adapter for this navigation. |
290
+ | `getFetch` | Supplies a custom fetch implementation for the underlying client. |
291
+ | `location` | Custom `ILOidcLocation` adapter. |
667
292
 
668
- These components encapsulate the use of "@axa-fr/vanilla-oidc" in order to hide workflow complexity.
669
- Internally, native History API is used to be router library agnostic.
293
+ Custom status components receive `configurationName`. Set `configuration.loading_timeout_ms` to change the default 30-second loading watchdog, or a nonpositive value to disable it. See [`OidcProviderProps`](./src/OidcProvider.tsx) for the full type.
670
294
 
671
- More information about OIDC
295
+ ## Routing and Next.js
672
296
 
673
- - [French : Augmentez la sécurité et la simplicité de votre Système d’Information OpenID Connect](https://medium.com/just-tech-it-now/augmentez-la-s%C3%A9curit%C3%A9-et-la-simplicit%C3%A9-de-votre-syst%C3%A8me-dinformation-avec-oauth-2-0-cf0732d71284)
674
- - [English : Increase the security and simplicity of your information system with openid connect](https://medium.com/just-tech-it-now/increase-the-security-and-simplicity-of-your-information-system-with-openid-connect-fa8c26b99d6d)
675
- - [English: youtube OIDC](https://www.youtube.com/watch?v=frIJfavZkUE&list=PL8EMdIH6Mzxy2kHtsVOEWqNz-OaM_D_fB&index=1)
676
- - [French: youtube OIDC](https://www.youtube.com/watch?v=H-mLMGzQ_y0&list=PL8EMdIH6Mzxy2kHtsVOEWqNz-OaM_D_fB&index=2)
297
+ ### Client-side routers
677
298
 
678
- ## NextJS
299
+ The default navigation uses the browser History API and dispatches `popstate`. Keep `OidcProvider` mounted on callback URLs. Protect route elements with `OidcSecure`; no particular router package is required.
679
300
 
680
- To work with NextJS you need to inject your own history surcharge like the sample below.
301
+ For a router-specific integration, provide `navigateAfterCallback` to perform and await the router's navigation, or `withCustomHistory` to replace the default history adapter. These options belong on `OidcProvider`.
681
302
 
682
- **component/layout.js**
303
+ The library retains hash-route callback matching for legacy integrations, but OAuth redirect URIs must not contain a fragment. Prefer path-based callback URLs for new deployments, even if the rest of the application uses a hash router. Existing hash-callback setups depend on provider-specific behavior. Interactive and silent callback URLs must be different.
683
304
 
684
- ```javascript
685
- import { OidcProvider } from '@axa-fr/react-oidc';
686
- import { useRouter } from 'next/router';
305
+ ### Next.js
687
306
 
688
- const configuration = {
689
- client_id: 'interactive.public.short',
690
- redirect_uri: 'http://localhost:3001/#authentication/callback',
691
- silent_redirect_uri: 'http://localhost:3001/#authentication/silent-callback', // Optional activate silent-login that use cookies between OIDC server and client javascript to restore the session
692
- scope: 'openid profile email api offline_access',
693
- authority: 'https://demo.duendesoftware.com',
694
- par: 'auto',
695
- };
307
+ Keep this browser library behind a client-only boundary: do not access `window` or initialize the OIDC client while rendering on the server. In the App Router, `'use client'` alone does not disable prerendering; use an appropriate client-only mounting or dynamic-import strategy.
696
308
 
697
- const onEvent = (configurationName, eventName, data) => {
698
- console.log(`oidc:${configurationName}:${eventName}`, data);
699
- };
309
+ The repository's [Next.js demo](../../examples/nextjs-demo/README.md) uses the **Pages Router** and a custom history adapter. For an initialized client-only provider using `next/router`, a post-login navigation adapter can look like this:
310
+
311
+ ```tsx
312
+ import { useRouter } from 'next/router';
313
+ import { OidcProvider } from '@axa-fr/react-oidc';
700
314
 
701
- export default function Layout({ children }) {
315
+ function ClientAuth({ children }: React.PropsWithChildren): React.JSX.Element {
702
316
  const router = useRouter();
703
- const withCustomHistory = () => {
704
- return {
705
- replaceState: url => {
706
- router
707
- .replace({
708
- pathname: url,
709
- })
710
- .then(() => {
711
- window.dispatchEvent(new Event('popstate'));
712
- });
713
- },
714
- };
715
- };
716
317
 
717
318
  return (
718
- <>
719
- <OidcProvider
720
- configuration={configuration}
721
- onEvent={onEvent}
722
- withCustomHistory={withCustomHistory}
723
- >
724
- <main>{children}</main>
725
- </OidcProvider>
726
- </>
319
+ <OidcProvider
320
+ configuration={configuration}
321
+ navigateAfterCallback={async (path: string): Promise<void> => {
322
+ await router.replace(path);
323
+ window.dispatchEvent(new Event('popstate'));
324
+ }}
325
+ >
326
+ {children}
327
+ </OidcProvider>
727
328
  );
728
329
  }
729
330
  ```
730
331
 
731
- For more information checkout the [NextJS React OIDC demo](https://github.com/AxaGuilDEv/react-oidc/tree/master/packages/nextjs-demo)
332
+ Here `configuration` is your browser-side OIDC configuration. Do not copy `next/router` into an App Router application; adapt to that router's APIs and navigation lifecycle. This package does not provide server-side route protection or a server session.
732
333
 
733
- ## Hash route
334
+ ## Named configurations
734
335
 
735
- `react-oidc` work also with hash router.
336
+ Use names to separate identity providers or sessions with different scopes. Give each configuration distinct callback URLs and, for worker mode, a matching trusted-domain entry.
736
337
 
737
- ```javascript
738
- export const configurationIdentityServerWithHash = {
739
- client_id: 'interactive.public.short',
740
- redirect_uri: window.location.origin + '#authentication-callback',
741
- silent_redirect_uri: window.location.origin + '#authentication-silent-callback',
742
- scope: 'openid profile email api offline_access',
743
- authority: 'https://demo.duendesoftware.com',
744
- par: 'auto',
745
- refresh_time_before_tokens_expiration_in_second: 70,
746
- service_worker_relative_url: '/OidcServiceWorker.js',
747
- service_worker_only: false,
748
- };
338
+ ```tsx
339
+ <OidcProvider configuration={accountConfiguration}>
340
+ <OidcProvider configuration={paymentsConfiguration} configurationName="payments">
341
+ <App />
342
+ </OidcProvider>
343
+ </OidcProvider>
344
+ ```
345
+
346
+ Select the name explicitly; nesting does not change the hooks' default name:
347
+
348
+ ```tsx
349
+ const { login, isAuthenticated } = useOidc('payments');
350
+ const { fetch: paymentsFetch } = useOidcFetch(undefined, 'payments');
749
351
  ```
352
+
353
+ Use `<OidcSecure configurationName="payments">` for that session's protected UI. Token and user hooks also accept a configuration name.
354
+
355
+ ## Errors and missing providers
356
+
357
+ `OidcError`, `OidcErrorCode`, `isOidcError`, `OidcStateError`, `OidcStateErrorCode`, `isOidcStateError`, and the PAR error classes/guards are re-exported from this package. Use stable codes and phases, not string matching, for error handling.
358
+
359
+ See the [core errors and events guide](../oidc-client/README.md#errors-and-events) for renewal errors, missing/mismatched state, missing nonces, retryability, and recovery. The provider's custom error/session-loss screens and `onEvent` callback are the React integration points. For strict renewal outside a hook, use `OidcClient.getOrThrow(name).renewTokensOrThrowAsync()`.
360
+
361
+ When no client has been initialized for a name, `useOidc`, `useOidcUser`, `useOidcAccessToken`, and `useOidcIdToken` warn once per name and return unauthenticated/null defaults. This is useful in tests and Storybook, but does not initialize authentication.
362
+
363
+ `OidcClient.get(name)` returns `null` for a missing client; `getOrThrow(name)` fails explicitly. `OidcSecure` and requests made through `useOidcFetch` require initialization and remain fail-fast. Mount a matching provider before using them.
364
+
365
+ ## Examples and further reading
366
+
367
+ - [React demo](../../examples/react-oidc-demo/README.md) — routes, hooks, worker options, and named configurations.
368
+ - [Next.js demo](../../examples/nextjs-demo/README.md) — Pages Router integration.
369
+ - [Core client guide and API](../oidc-client/README.md).
370
+ - [Service-worker protocol](../oidc-client-service-worker/PROTOCOL.md).
371
+ - [Service-worker package guide](../oidc-client-service-worker/README.md).
372
+ - [FAQ and deployment guidance](../../FAQ.md).
373
+
374
+ The demos use the repository's pnpm workspace. Follow their READMEs for setup rather than installing each package separately.