oidc-client-ts

repository·main·Indexed 23 days ago

https://github.com/authts/oidc-client-ts

A TypeScript library for implementing OpenID Connect (OIDC) and OAuth2 in browser-based applications, focusing on modern OAuth 2.1 compatible flows. It provides a high-level UserManager API for session and claims management, and a low-level OidcClient API for raw protocol support. Supported flows include Authorization Code Grant with PKCE, Resource Owner Password Credentials (ROPC), Refresh Token, and Silent Refresh Token in iframe. Implicit grant is not supported.

Tokens
17K
Snippets
26
Records
96
Agent score
84%

What's inside oidc-client-ts

  1. Overview of oidc-client-ts

    main

    oidc-client-ts is a library providing OpenID Connect (OIDC) and OAuth2 protocol support for client-side, browser-based JavaScript applications. It manages user sessions and access tokens.

    Supported Protocols

    This library implements protocols aligned with OAuth 2.1. Note that the implicit grant is not supported.

    Supported flows include:

    • Authorization Code Grant with Proof Key for Code Exchange (PKCE)
    • Authorization Code Grant
    • Resource Owner Password Credentials (ROPC) Grant
    • Refresh Token Grant
    • Silent Refresh Token in iframe Flow
  2. Understand the Authorization Code Grant flow

    main

    The Authorization Code Grant is an OAuth 2.0 protocol (RFC 6749) where an application exchanges an authorization code for access and ID tokens.

    Workflow Steps:

    1. Initiation: The user clicks a sign-in link in the application.
    2. Redirection: The application uses signinRedirect() or signinPopup() to request an authorization code from the Identity Provider.
    3. Authentication: The Identity Provider authenticates the user and redirects back to the application with an authorization code.
    4. Exchange: The application calls signinCallback() to send the authorization code and client secret to the Identity Provider in exchange for tokens.
    5. Usage: The application retrieves the access token via getUser()?.access_token to make requests to protected APIs.
  3. Manage logging levels and custom loggers

    main

    The library provides a global Log namespace to control the verbosity of logs and to inject custom logging implementations. This is useful for integrating the library's logs into your application's existing logging infrastructure.

    Setting the Log Level

    Use Log.setLevel(value) to set the current logging level. The available levels are defined in the Log enum:

    • Log.NONE (0): No logging.
    • Log.ERROR (1): Only error messages.
    • Log.WARN (2): Errors and warnings.
    • Log.INFO (3): Errors, warnings, and info messages.
    • Log.DEBUG (4): All messages, including debug logs.

    Using a Custom Logger

    To use your own logging logic, implement the ILogger interface and pass it to Log.setLogger(value). The interface requires the following methods:

    • debug(...args: unknown[]): void
    • error(...args: unknown[]): void
    • info(...args: unknown[]): void
    • warn(...args: unknown[]): void
    export enum Log {
        // (undocumented)
        DEBUG = 4,
        ERROR = 1,
        INFO = 3,
        NONE = 0,
        WARN = 2
    }
    
    // (undocumented)
    export namespace Log {
        // (undocumented)
        export function reset(): void;
        // (undocumented)
        export function setLevel(value: Log): void;
        // (undocumented)
        export function setLogger(value: ILogger): void;
    }
  4. Understand the Resource Owner Password Credentials (ROPC) Grant

    main

    The Resource Owner Password Credentials (ROPC) grant is an OAuth 2.0 flow where the client application collects the user's username and password directly and exchanges them with the Identity Provider for tokens.

    ⚠️ Critical Security Warning

    This flow is not part of the OpenID Connect standard and has been removed in the OAuth 2.1 draft. It carries significant risks:

    • Credential Exposure: The client application handles the user's raw credentials. The RFC mandates that the client MUST discard these credentials immediately after obtaining tokens, but this cannot be technically enforced by the Identity Provider.
    • Increased Attack Surface: If the client application is compromised (e.g., via XSS), the user's actual credentials are stolen, potentially granting access to other services. In contrast, the Authorization Code Flow only exposes access tokens.
    • Usage Recommendation: Do NOT use this as a replacement for the Authorization Code flow. It should only be used as a replacement for classic form-based authentication when both the client and the Identity Provider are under the same security domain or organization.

    Workflow

    1. The user initiates sign-in within the application.
    2. The application calls signinResourceOwnerCredentials() to send the credentials to the Identity Provider.
    3. The Identity Provider validates the credentials and returns an access token and an ID token.
    4. The application uses the access token to request protected data from its API.
  5. How the Silent Refresh Token in iframe Flow works

    main

    The Silent Refresh Token in iframe flow allows an application to refresh its access and ID tokens without a full page reload or user interaction. It relies on the OAuth2.0 Authorization Code Grant (with or without PKCE) and uses a hidden iframe to handle the server callback.

    Prerequisites:

    • The user must have an active authenticated session with the Identity Provider (IdP).
    • The IdP must store a session cookie that is accessible to the iframe during the request.

    The Flow Lifecycle:

    1. The application initiates the process using signinSilent().
    2. A hidden iframe is loaded to perform the Authorization Code request. If PKCE is used, the code_challenge is included.
    3. The Identity Provider validates the session cookie and redirects back to the application's callback URL within that iframe.
    4. The application's signinCallback() method intercepts the authorization code from the iframe and exchanges it (along with the code_verifier or client_secret) for new access and ID tokens.
    5. The new tokens are then available via getUser()?.access_token for subsequent API calls.
    sequenceDiagram
      App->>Hidden iframe: Load silent<br/>Authorization Code Grant<br/>in an iframe (1)
    
      activate Hidden iframe
      Note right of Hidden iframe: PKCE: Generate code_verifier and<br/>code_challenge
      Hidden iframe->>Identity Provider: Authorization code request (1)
      deactivate Hidden iframe
      Note right of Hidden iframe: PKCE: with code_challenge
      Note right of Identity Provider: Validate session cookie
    
      Identity Provider->>Hidden iframe: Authorization code (2)
      activate Hidden iframe
      Hidden iframe->>App: Notify parent window (3)
      deactivate Hidden iframe
    
      activate App
      App->>Identity Provider: Authorization code & code verifier or client secret (3)
      Note right of Identity Provider: Validate authorization code &<br/>code verifier or client secret
      Identity Provider->>App: Access token and ID token (3)
      deactivate App
    
      App->>Your API: Request protected data with refreshed access token (4)
  6. Use IndexedDbDPoPStore for secure DPoP storage

    main

    The IndexedDbDPoPStore is the recommended default implementation of the DPoPStore interface. It uses IndexedDb to store CryptoKeyPair objects with non-extractable private keys.

    Why use IndexedDb? Unlike localStorage or sessionStorage, IndexedDb allows storing keys that can be used for signing operations without allowing the private key material to be extracted directly. Storing keys as plain text in localStorage is not recommended as it exposes them to attackers.

  7. How UserManager and OidcClient differ

    main

    The library provides two main classes depending on the level of abstraction you need:

    • UserManager: A high-level API designed for most web applications. It handles signing users in/out, managing user sessions, and managing user claims.
    • OidcClient: A low-level API that provides raw OIDC/OAuth2 protocol support without the session management abstractions of UserManager.

    Most developers should use UserManager.

  8. Configure UserManager settings

    main

    The UserManager constructor requires a settings object of type UserManagerSettings.

    Required Settings

    To initialize the manager, you must provide:

    • authority: The URL of the OIDC/OAuth2 provider.
    • client_id: Your client application's identifier registered with the provider.
    • redirect_uri: The URI in your application where the provider will redirect after authentication.

    Handling Providers without CORS on Metadata

    If your provider's metadata endpoint does not support CORS, the library cannot automatically discover settings via the authority URL. In this case, you must manually provide a metadata object containing:

    • issuer
    • authorization_endpoint
    • userinfo_endpoint
    • end_session_endpoint

    You can also use metadataSeed to add additional values to the results of a discovery request.

  9. Configure logging in oidc-client-ts

    main

    The library supports custom logging. By default, no logger is configured. To enable logging, use Log.setLogger() with an object that implements info, warn, and error methods (accepting a params array).

    To control verbosity, use Log.setLevel() with one of the following levels:

    • Log.NONE
    • Log.ERROR
    • Log.WARN
    • Log.INFO (Default)

    To quickly enable browser console logging:

    import { Log } from 'oidc-client-ts';
    Log.setLogger(console);
  10. Migrate from oidc-client v1.11.5 to oidc-client-ts v2.0.0

    main

    When upgrading to v2.0.0, note the following changes:

    OidcClientSettings Changes

    • Required Properties: authority, client_id, and redirect_uri are now mandatory.
    • Renamed Properties:
      • clockSkew $\rightarrow$ clockSkewInSeconds
      • staleStateAge $\rightarrow$ staleStateAgeInSeconds
    • Defaults: loadUserInfo now defaults to false (previously true).
    • Flow Restrictions: response_type is restricted to code flow only. PKCE is required for all OAuth clients using the authorization code flow. Hybrid flows are not supported.
    • Removed: ResponseValidatorCtor and MetadataServiceCtor. You may need to extend OidcClient or UserManager classes to alter behavior.

    UserManagerSettings Changes

    • Renamed Properties:
      • accessTokenExpiringNotificationTime $\rightarrow$ accessTokenExpiringNotificationTimeInSeconds
      • silentRequestTimeout (ms) $\rightarrow$ silentRequestTimeoutInSeconds
      • checkSessionInterval (ms) $\rightarrow$ checkSessionIntervalInSeconds
      • revokeAccessTokenOnSignout $\rightarrow$ revokeTokensOnSignout
    • New Default Values:
      • automaticSilentRenew: true (previously false)
      • validateSubOnSilentRenew: true (previously false)
      • includeIdTokenInSilentRenew: false (previously true)
      • monitorSession: false (previously true)
    • Popup Features: popupWindowFeatures changed from a string to a dictionary. Default dimensions are now responsive to the opener window.
    • Token Revocation: A new property revokeTokenTypes: ('access_token' | 'refresh_token')[] was added. By default, UserManager attempts to revoke both when revokeTokensOnSignout is true. Sign out will now fail if revocations fail.

    UserManager API Changes

    • Signout Popup: The shorthand signoutPopupCallback(true) is no longer supported. Use signoutPopupCallback(undefined, true) or signoutPopupCallback(location.href, true).
    • Renamed Method: revokeAccessToken() $\rightarrow$ revokeTokens(types?). This method will now throw if any specified revocation fails.

    Log and User Changes

    • Log API: Log.level and Log.logger getters/setters are replaced by Log.setLevel() and Log.setLogger().
    • User Expiry: User.expired now returns true when expires_at is set to 0 (previously false).
  11. Perform a silent token refresh

    main

    To trigger a silent token refresh using an iframe, use the signinSilent() method. This method initiates the background authorization request. Once the flow completes, you can retrieve the refreshed tokens using getUser().

    Steps:

    1. Call signinSilent() to start the flow.
    2. Ensure your application is configured to handle the callback via signinCallback().
    3. Access the new token using getUser()?.access_token.
  12. Migrate from oidc-client v2.4.0 to oidc-client-ts v3.0.0

    main

    When upgrading to v3.0.0, note the following changes:

    Crypto Implementation

    • The crypto-js library has been removed in favor of the native browser crypto/crypto.subtle module.
    • Requirement: You must use modern browsers. If you need to support older browsers, continue using v2.x.

    OidcClientSettings Changes

    • Removed Properties: clockSkewInSeconds, userInfoJwtIssuer, and refreshTokenCredentials (use fetchRequestCredentials instead).
    • Claim Merging: mergeClaims is replaced by mergeClaimsStrategy. To approximate previous behavior, use mergeClaimsStrategy: { array: "merge" }.
    • Response Mode: The default value for response_mode changed from query to undefined.