Light, Secure, Pure Javascript OIDC (Open ID Connect) Client. We provide also a REACT wrapper (compatible NextJS, etc.).
Installations
npm install @axa-fr/oidc-client
Developer Guide
Typescript
Yes
Module System
ESM
Node Version
18.20.5
NPM Version
10.8.2
Score
90.4
Supply Chain
99.1
Quality
98.3
Maintenance
100
Vulnerability
100
License
Releases
Contributors
Languages
TypeScript (94.18%)
JavaScript (5.31%)
Shell (0.5%)
Developer
AxaFrance
Download Statistics
Total Downloads
1,142,270
Last Day
1,580
Last Week
11,721
Last Month
91,310
Last Year
980,310
GitHub Statistics
612 Stars
1,235 Commits
162 Forks
22 Watching
53 Branches
55 Contributors
Bundle Size
49.99 kB
Minified
14.44 kB
Minified + Gzipped
Package Meta Information
Latest Version
7.24.1
Package Id
@axa-fr/oidc-client@7.24.1
Unpacked Size
326.95 kB
Size
82.78 kB
File Count
99
NPM Version
10.8.2
Node Version
18.20.5
Publised On
10 Jan 2025
Total Downloads
Cumulative downloads
Total Downloads
1,142,270
Last day
-8.4%
1,580
Compared to previous day
Last week
-39.4%
11,721
Compared to previous week
Last month
-5.2%
91,310
Compared to previous month
Last year
505.3%
980,310
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
@axa-fr/oidc-client
@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. @axa-fr/oidc-client is a pure javascript library. It works with any JavaScript framework or library.
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.
- Try the react demo at https://black-rock-0dc6b0d03.1.azurestaticapps.net/ (most advanced)
- Try the pure javascript demo at https://icy-glacier-004ab4303.2.azurestaticapps.net/
About
@axa-fr/oidc-client is:
- Secure :
- With Demonstrating Proof of Possession (DPoP), your access_token and refresh_token are not usable outside your browser context (big protection)
- 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
section) - OIDC using client side Code Credential Grant with pkce only
- Lightweight : Unpacked Size on npm is 274 kB
- Simple
- refresh_token and access_token are auto refreshed in background
- 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
- Multiple Authentication :
- You can authenticate many times to the same provider with different scope (for example you can acquire a new 'payment' scope for a payment)
- You can authenticate to multiple different providers inside the same SPA (single page application) website
- Flexible :
- Work with Service Worker (more secure) and without for older browser (less secure).
- You can disable Service Worker if you want (but less secure) and just use SessionStorage or LocalStorage mode.
The service worker catch access_token and refresh_token that will never be accessible to the client.
Getting Started
1npm install @axa-fr/oidc-client --save 2 3# To install or update OidcServiceWorker.js file, you can run 4node ./node_modules/@axa-fr/oidc-client/bin/copy-service-worker-files.mjs public 5 6# If you have a "public" folder, the 2 files will be created : 7# ./public/OidcServiceWorker.js <-- will be updated at each "npm install" 8# ./public/OidcTrustedDomains.js <-- won't be updated if already exist
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 :
1 "scripts": { 2 ... 3 "postinstall": "node ./node_modules/@axa-fr/oidc-client/bin/copy-service-worker-files.mjs public" 4 },
If you need a very secure mode where refresh_token and access_token will be hide behind a service worker that will proxify requests. The only file you should edit is "OidcTrustedDomains.js".
1// OidcTrustedDomains.js 2 3// Add bellow trusted domains, access tokens will automatically injected to be send to 4// trusted domain can also be a path like https://www.myapi.com/users, 5// then all subroute like https://www.myapi.com/useers/1 will be authorized to send access_token to. 6 7// Domains used by OIDC server must be also declared here 8const trustedDomains = { 9 default: { 10 oidcDomains: ['https://demo.duendesoftware.com'], 11 accessTokenDomains: ['https://www.myapi.com/users'], 12 }, 13}; 14 15// Service worker will continue to give access token to the JavaScript client 16// Ideal to hide refresh token from client JavaScript, but to retrieve access_token for some 17// scenarios which require it. For example, to send it via websocket connection. 18trustedDomains.config_show_access_token = { 19 oidcDomains: ['https://demo.duendesoftware.com'], 20 accessTokenDomains: ['https://www.myapi.com/users'], 21 showAccessToken: false, 22 // convertAllRequestsToCorsExceptNavigate: false, // default value is false 23 // setAccessTokenToNavigateRequests: true, // default value is true 24}; 25 26// DPoP (Demonstrating Proof of Possession) will be activated for the following domains 27trustedDomains.config_with_dpop = { 28 domains: ['https://demo.duendesoftware.com'], 29 demonstratingProofOfPossession: true, 30 demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: true, // default value is false, inject DPOP token only when DPOP header is present 31 // Optional, more details bellow 32 /*demonstratingProofOfPossessionConfiguration: { 33 importKeyAlgorithm: { 34 name: 'ECDSA', 35 namedCurve: 'P-256', 36 hash: {name: 'ES256'} 37 }, 38 signAlgorithm: {name: 'ECDSA', hash: {name: 'SHA-256'}}, 39 generateKeyAlgorithm: { 40 name: 'ECDSA', 41 namedCurve: 'P-256' 42 }, 43 digestAlgorithm: { name: 'SHA-256' }, 44 jwtHeaderAlgorithm : 'ES256' 45 }*/ 46}; 47 48// Setting allowMultiTabLogin to true will enable storing login-specific parameters (state, nonce, code verifier) 49// separately for each tab. This will prevent errors when logins are initiated from multiple tabs. 50trustedDomains.config_multi_tab_login = { 51 domains: ['https://demo.duendesoftware.com'], 52 allowMultiTabLogin: true, 53};
The code of the demo :
1import { OidcClient } from '@axa-fr/oidc-client'; 2 3export const configuration = { 4 client_id: 'interactive.public.short', 5 redirect_uri: window.location.origin + '/#/authentication/callback', 6 silent_redirect_uri: window.location.origin + '/#/authentication/silent-callback', 7 scope: 'openid profile email api offline_access', 8 authority: 'https://demo.duendesoftware.com', 9 service_worker_relative_url: '/OidcServiceWorker.js', // just comment that line to disable service worker mode 10 service_worker_only: false, 11 demonstrating_proof_of_possession: false, 12}; 13 14const href = window.location.href; 15const oidcClient = OidcClient.getOrCreate()(configuration); 16 17// Use the fetch bellow to inject access_token and DPOP tokens automatically 18const oidcFetch = oidcClient.fetchWithTokens(fetch); 19 20// You can inject you own fetch (default Fetch Interface) function and location object (respecting IOidcLocation interface) 21// import {OidcLocation} from '@axa-fr/oidc-client' 22// const oidcClient = OidcClient.getOrCreate(() => fetch, new OidcLocation())(configuration); 23 24console.log(href); 25 26oidcClient.tryKeepExistingSessionAsync().then(() => { 27 if (href.includes(configuration.redirect_uri)) { 28 oidcClient.loginCallbackAsync().then(() => { 29 window.location.href = '/'; 30 }); 31 document.body.innerHTML = `<div> 32 <h1>@axa-fr/oidc-client demo</h1> 33 <h2>Loading</h2> 34 </div>`; 35 return; 36 } 37 38 let tokens = oidcClient.tokens; 39 40 if (tokens) { 41 // @ts-ignore 42 window.logout = () => oidcClient.logoutAsync(); 43 document.body.innerHTML = `<div> 44 <h1>@axa-fr/oidc-client demo</h1> 45 <button onclick="window.logout()">Logout</button> 46 <h2>Authenticated</h2> 47 <pre>${JSON.stringify(tokens, null, '\t')}</pre> 48 </div>`; 49 } else { 50 // @ts-ignore 51 window.login = () => oidcClient.loginAsync('/'); 52 document.body.innerHTML = `<div> 53 <h1>@axa-fr/oidc-client demo</h1> 54 <button onclick="window.login()">Login</button> 55 </div>`; 56 } 57});
Configuration
1 2const configuration = { 3 client_id: String.isRequired, // oidc client id 4 redirect_uri: String.isRequired, // oidc redirect url 5 silent_redirect_uri: String, // Optional activate silent-signin that use cookies between OIDC server and client javascript to restore sessions 6 silent_login_uri: String, // Optional, route that triggers the signin 7 silent_login_timeout: Number, // Optional, default is 12000 milliseconds 8 scope: String.isRequired, // oidc scope (you need to set "offline_access") 9 authority: String.isRequired, 10 storage: Storage, // Default sessionStorage, you can set localStorage, but it is less secure against XSS attacks 11 authority_configuration: { 12 // Optional for providers that do not implement OIDC server auto-discovery via a .wellknown URL 13 authorization_endpoint: String, 14 token_endpoint: String, 15 userinfo_endpoint: String, 16 end_session_endpoint: String, 17 revocation_endpoint: String, 18 check_session_iframe: String, 19 issuer: String, 20 }, 21 refresh_time_before_tokens_expiration_in_second: Number, // default is 120 seconds 22 service_worker_relative_url: String, 23 service_worker_keep_alive_path: String, // default is "/" 24 service_worker_only: Boolean, // default false, if true, the user will not be able to login if the service worker is not available on its browser 25 service_worker_activate: () => boolean, // you can take the control of the service worker default activation which use user agent string, if return false, the service worker mode will not be used 26 service_worker_update_require_callback: (registration:any, stopKeepAlive:Function) => Promise<void>, // callback called when service worker need to be updated, you can take the control of the update process 27 service_worker_register: (url: string) => Promise<ServiceWorkerRegistration>, // Optional, you can take the control of the service worker registration 28 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) 29 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) 30 authority_time_cache_wellknowurl_in_second: 60 * 60, // Time to cache in seconds of the openid well-known URL, default is 1 hour 31 authority_timeout_wellknowurl_in_millisecond: 10000, // Timeout in milliseconds of the openid well-known URL, default is 10 seconds, then an error is thrown 32 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/ 33 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" 34 token_automatic_renew_mode: TokenAutomaticRenewMode.AutomaticOnlyWhenFetchExecuted, // Optional, default is TokenAutomaticRenewMode.AutomaticBeforeTokensExpiration 35 // TokenAutomaticRenewMode.AutomaticBeforeTokensExpiration: renew tokens automatically before they expire 36 // TokenAutomaticRenewMode.AutomaticOnlyWhenFetchExecuted: renew tokens automatically only when fetch is executed 37 // It requires you to use fetch given by oidcClient.fetchWithTokens(fetch) or to use oidcClient.getValidTokenAsync() 38 logout_tokens_to_invalidate: Array<string>, // Optional tokens to invalidate during logout, default: ['access_token', 'refresh_token'] 39 location: ILOidcLocation, // Optional, default is window.location, you can inject your own location object respecting the ILOidcLocation interface 40 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 41 demonstrating_proof_of_possession_configuration: DemonstratingProofOfPossessionConfiguration // Optional, more details bellow 42}; 43 44 45interface DemonstratingProofOfPossessionConfiguration { 46 generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams, 47 digestAlgorithm: AlgorithmIdentifier, 48 importKeyAlgorithm: AlgorithmIdentifier | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | AesKeyAlgorithm, 49 signAlgorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams, 50 jwtHeaderAlgorithm: string 51}; 52 53// default value of demonstrating_proof_of_possession_configuration 54const defaultDemonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration ={ 55 importKeyAlgorithm: { 56 name: 'ECDSA', 57 namedCurve: 'P-256', 58 hash: {name: 'ES256'} 59 }, 60 signAlgorithm: {name: 'ECDSA', hash: {name: 'SHA-256'}}, 61 generateKeyAlgorithm: { 62 name: 'ECDSA', 63 namedCurve: 'P-256' 64 }, 65 digestAlgorithm: { name: 'SHA-256' }, 66 jwtHeaderAlgorithm : 'ES256' 67}; 68 69
API
1/** 2 * OidcClient is a class that acts as a wrapper around the `Oidc` object. It provides methods to handle event subscriptions, logins, logouts, token renewals, user information, etc. 3 */ 4export class OidcClient { 5 /** 6 * Creates an instance of OidcClient using a provided `Oidc` object. 7 * @param oidc The instance of the underlying Oidc object to use. 8 */ 9 constructor(oidc: Oidc); 10 11 /** 12 * Subscribes a function to events emitted by the underlying Oidc object. 13 * @param func The function to be called when an event is emitted. 14 * @returns A string that identifies the subscription and can be used to unsubscribe later. 15 */ 16 subscribeEvents(func: EventSubscriber): string; 17 18 /** 19 * Removes a subscription to a specified event. 20 * @param id The identifier of the subscription to remove, obtained during the initial subscription. 21 */ 22 removeEventSubscription(id: string): void; 23 24 /** 25 * Publishes an event with the specified name and associated data. 26 * @param eventName The name of the event to publish. 27 * @param data The data associated with the event. 28 */ 29 publishEvent(eventName: string, data: any): void; 30 31 /** 32 * Creates a new instance of OidcClient using a fetch retrieval function `getFetch`, with a given OIDC configuration and an optional name. 33 * @param getFetch The function to retrieve the `Fetch` object. 34 * @param configuration The OIDC configuration to use for creating the OidcClient instance. 35 * @param name The optional name for the created OidcClient instance. 36 * @returns A new instance of OidcClient with the specified configuration. 37 */ 38 static getOrCreate(getFetch: () => Fetch)(configuration: OidcConfiguration, name?: string): OidcClient; 39 40 /** 41 * Retrieves an existing OidcClient instance with the specified name, or creates a new instance if it does not exist. 42 * @param name The name of the OidcClient instance to retrieve. 43 * @returns The existing OidcClient instance or a new instance with the specified name. 44 */ 45 static get(name?: string): OidcClient; 46 47 /** 48 * The names of the events supported by the Oidc class. 49 */ 50 static eventNames: Oidc.eventNames; 51 52 /** 53 * Attempts to keep the existing user session by calling the function of the underlying Oidc object. 54 * @returns A promise resolved with `true` if the user session was kept, otherwise `false`. 55 */ 56 tryKeepExistingSessionAsync(): Promise<boolean>; 57 58 /** 59 * Starts the OIDC login process with specified options. 60 * @param callbackPath The callback path for authentication. 61 * @param extras Additional parameters to send to the OIDC server during the login request. 62 * @param isSilentSignin Indicates if the login is silent. 63 * @param scope The OIDC scope for the login request. 64 * @param silentLoginOnly Indicates if only silent login is allowed. 65 * @returns A promise resolved with the login information, or rejected with an error. 66 */ 67 loginAsync(callbackPath?: string, extras?: StringMap, isSilentSignin?: boolean, scope?: string, silentLoginOnly?: boolean): Promise<unknown>; 68 69 /** 70 * Starts the OIDC logout process with specified options. 71 * @param callbackPathOrUrl The callback path or URL to use after logout. 72 * @param extras Additional parameters to send to the OIDC server during the logout request. 73 * {"no_reload:oidc":"true"} to avoid the page reload after logout. 74 * you can add extras like {"client_secret:revoke_refresh_token":"secret"} to revoke the refresh token with extra client secret. Any key ending with ":revoke_refresh_token" will be used to revoke the refresh token. 75 * you can add extras like {"client_secret:revoke_access_token":"secret"} to revoke the access token with extra client secret. Any key ending with ":revoke_access_token" will be used to revoke the access token. 76 * @returns A promise resolved when the logout is completed. 77 */ 78 logoutAsync(callbackPathOrUrl?: string | null | undefined, extras?: StringMap): Promise<void>; 79 80 /** 81 * Performs the silent login process and retrieves user information. 82 * @returns A promise resolved when the silent login process is completed. 83 */ 84 silentLoginCallbackAsync(): Promise<void>; 85 86 /** 87 * Renews the user's OIDC tokens. 88 * @param extras Additional parameters to send to the OIDC server during the token renewal request. 89 * @returns A promise resolved when the token renewal is completed. 90 */ 91 renewTokensAsync(extras?: StringMap): Promise<void>; 92 93 /** 94 * Performs the callback process after a successful login and automatically renews tokens. 95 * @returns A promise resolved with the callback information, or rejected with an error. 96 */ 97 loginCallbackAsync(): Promise<LoginCallback>; 98 99 /** 100 * Retrieves the current OIDC tokens for the user. 101 */ 102 get tokens(): Tokens; 103 104 /** 105 * Retrieves the current OIDC configuration used by the OidcClient instance. 106 */ 107 get configuration(): OidcConfiguration; 108 109 /** 110 * Retrieves the valid OIDC token for the user. 111 * @param waitMs The maximum wait time in milliseconds to obtain a valid token. 112 * @param numberWait The number of attempts to obtain a valid token. 113 * @returns A promise resolved with the valid token, or rejected with an error. 114 */ 115 async getValidTokenAsync(waitMs = 200, numberWait = 50): Promise<ValidToken>; 116 117 /** 118 * Retrieves a new fetch function that inject bearer tokens (also DPOP tokens). 119 * @param fetch The current fetch function to use 120 * @param demonstrating_proof_of_possession Indicates whether the demonstration of proof of possession should be used. 121 * @returns Fetch A new fectch function that inject bearer tokens (also DPOP tokens). 122 */ 123 fetchWithTokens(fetch: Fetch, demonstrating_proof_of_possession=false): Fetch; 124 125 /** 126 * Retrieves OIDC user information. 127 * @param noCache Indicates whether user information should be retrieved bypassing the cache. 128 * @param demonstrating_proof_of_possession Indicates whether the demonstration of proof of possession should be used. 129 * @returns A promise resolved with the user information, or rejected with an error. 130 */ 131 async userInfoAsync<T extends OidcUserInfo = OidcUserInfo>(noCache = false, demonstrating_proof_of_possession=false): Promise<T>; 132 133 /** 134 * Generate Demonstration of proof of possession. 135 * @param accessToken The access token to use. 136 * @param url The url to use. 137 * @param method The method to use. 138 * @param extras Additional parameters to send to the OIDC server during the demonstration of proof of possession request. 139 * @returns A promise resolved with the proof of possession. 140 */ 141 async generateDemonstrationOfProofOfPossessionAsync(accessToken:string, url:string, method:string, extras:StringMap= {}): Promise<string>; 142} 143
Run The Demo
1git clone https://github.com/AxaFrance/oidc-client.git 2cd oidc-client 3 4# oidc client demo 5cd /examples/oidc-client-demo 6pnpm install 7pnpm start 8# then navigate to http://localhost:5174 9
How It Works
This component is a pure vanilla JS OIDC client library agnostic to any framework. It is a real alternative to existing oidc-client libraries.
More information about OIDC
- French : Augmentez la sécurité et la simplicité de votre Système d’Information OpenID Connect
- English : Increase the security and simplicity of your information system with openid connect
- English: youtube OIDC
- French: youtube OIDC
Hash route
@axa-fr/oidc-client
work also with hash route.
1export const configurationIdentityServerWithHash = { 2 client_id: 'interactive.public.short', 3 redirect_uri: window.location.origin + '#authentication-callback', 4 silent_redirect_uri: window.location.origin + '#authentication-silent-callback', 5 scope: 'openid profile email api offline_access', 6 authority: 'https://demo.duendesoftware.com', 7 refresh_time_before_tokens_expiration_in_second: 70, 8 service_worker_relative_url: '/OidcServiceWorker.js', 9 service_worker_only: false, 10};
No vulnerabilities found.
No security vulnerabilities found.