Auth0 React SDK

repository·main·Indexed 21 days ago

https://github.com/auth0/auth0-react

SDK for integrating Auth0 authentication into React Single Page Applications (SPAs). It manages OIDC/OAuth2 flows and provides the Auth0Provider component, the useAuth0 hook for managing user state and authentication actions, and higher-order components like withAuth0 and withAuthenticationRequired for class components and route protection.

Tokens
27.4K
Snippets
74
Records
90
Agent score
76%

What's inside @auth0/auth0-react

  1. How Online Refresh Tokens (ORTs) work

    main

    Online Refresh Tokens (ORTs) are a session-bound refresh token type. Unlike standard rotating offline tokens, ORTs are:

    • Session-bound: Valid only while the underlying Auth0 session is active. If the session ends (logout, expiry, or admin revocation), the ORT stops working.
    • Non-rotating: Refreshing an access token does not issue a new refresh token; the same ORT is reused for the life of the session.

    Requirements:

    • DPoP is mandatory: Because ORTs are non-rotating, you must use DPoP to bind the token to the browser's key pair to mitigate replay attacks. Set useDpop={true}.
    • Resource Server Config: The resource server must have allow_online_access enabled.
    • Limitation: ORTs do not currently support resource servers with Ephemeral Sessions enabled. If both are enabled, the token will be rejected with invalid_grant on the next refresh.
  2. Handle Session Expiry from Upstream IdP (IPSIE)

    main

    When using enterprise connections (like Okta) that support id_token_session_expiry_supported: true, Auth0 includes a session_expiry claim in the ID token. This claim is a Unix timestamp (in seconds) representing a hard ceiling for the local session.

    SDK Behavior

    When the session_expiry timestamp is reached, the SDK updates its state on the next call to getAccessTokenSilently, getUser, or getIdTokenClaims. There is no background timer; the state only updates when these methods are invoked.

    Upon reaching the ceiling:

    • isAuthenticated becomes false.
    • user becomes undefined.
    • getAccessTokenSilently() returns undefined (without throwing an error).

    Automatic Redirection

    If your routes are wrapped with the withAuthenticationRequired Higher-Order Component (HOC), no manual code changes are needed. The next time a component calls getAccessTokenSilently or getUser, the SDK state updates, and the HOC will automatically redirect the user to the login page.

    Note: A user sitting on a page that makes no calls to the SDK will remain in an 'authenticated' state in the React context until a call is made.

  3. How Multi-Factor Authentication (MFA) works in the SDK

    main

    MFA support is available via the mfa property from the useAuth0() hook. All MFA operations require an mfa_token which is provided in the error payload when an authentication attempt triggers an mfa_required error.

    There are two primary flows based on the mfa_requirements object in the error response:

    1. Challenge Flow: The user has already enrolled authenticators. You must follow the List Authenticators → Challenge → Verify flow.
    2. Enroll Flow: The user needs to set up MFA. You must follow the Enroll → Verify flow.
    NOTE

    Multi Factor Authentication support via SDKs is currently in Early Access. To request access to this feature, contact your Auth0 representative.

    // Example Challenge Flow Response
    {
      "error": "mfa_required",
      "error_description": "Multifactor authentication required",
      "mfa_token": "Fe26.2*...",
      "mfa_requirements": {
        "challenge": [
          { "type": "otp" },
          { "type": "email" }
        ]
      }
    }
    
    // Example Enroll Flow Response
    {
      "error": "mfa_required",
      "error_description": "Multifactor authentication required",
      "mfa_token": "Fe26.2*...",
      "mfa_requirements": {
        "enroll": [
          { "type": "otp" },
          { "type": "phone" }
        ]
      }
    }
  4. Update default scope behavior in v2

    main

    In v2, the SDK's handling of default scopes has changed:

    • If scope is omitted, it defaults to openid profile email.
    • If scope is explicitly provided, it only includes openid unless you manually add the other scopes.

    To maintain the same behavior as v1 when providing custom scopes, you must explicitly include profile and email in your authorizationParams.scope string.

    // v2: Must explicitly include profile and email if providing custom scopes
    <Auth0Provider
      authorizationParams={{
        scope: "profile email scope1"
      }}
    >
      <App />
    </Auth0Provider>
  5. Use Auth0 with React Class Components

    main

    To use Auth0 in a Class component, wrap the component with the withAuth0 higher-order component. This injects an auth0 prop into the component, which contains the same properties available via the useAuth0 hook (such as user, isAuthenticated, loginWithRedirect, etc.).

    import React, { Component } from 'react';
    import { withAuth0 } from '@auth0/auth0-react';
    
    class Profile extends Component {
      render() {
        // `this.props.auth0` has all the same properties as the `useAuth0` hook
        const { user } = this.props.auth0;
        return <div>Hello {user.name}</div>;
      }
    }
    
    export default withAuth0(Profile);
  6. Enable DPoP (Demonstrating Proof-of-Possession)

    main

    DPoP is an OAuth 2.0 extension that cryptographically binds tokens to a specific device to prevent token theft via XSS. It is disabled by default. To enable it, set useDpop={true} in the Auth0Provider configuration.

    Important considerations:

    • Only the ES256 algorithm is currently supported.
    • DPoP only applies to new user sessions created after enabling it. Existing sessions will continue using non-DPoP tokens until the user re-authenticates.
    • Using DPoP requires storing temporary data in the browser, which is cleared when logout() is called.
    • Supported flows: authorization_code, refresh_token, and urn:ietf:params:oauth:grant-type:token-exchange.
    <Auth0Provider
      domain="YOUR_AUTH0_DOMAIN"
      clientId="YOUR_AUTH0_CLIENT_ID"
      useDpop={true} // 👈
      authorizationParams={{ redirect_uri: window.location.origin }}
    >
  7. Perform a Custom Token Exchange (RFC 8693)

    main

    Use loginWithCustomTokenExchange to exchange an external subject token for Auth0 tokens. This implements the RFC 8693 token exchange grant type.

    Requirements:

    • subject_token_type must be a namespaced URI under your organization's control.
    • The external token must be validated in Auth0 Actions using strong cryptographic verification.
    • This method triggers the GET_ACCESS_TOKEN_COMPLETE action internally, so isLoading and isAuthenticated states in the SDK will behave normally.

    Note: The exchangeToken method is deprecated. Use loginWithCustomTokenExchange instead.

    import React, { useState } from 'react';
    import { useAuth0 } from '@auth0/auth0-react';
    
    const TokenExchange = () => {
      const { loginWithCustomTokenExchange } = useAuth0();
      const [tokens, setTokens] = useState(null);
      const [error, setError] = useState(null);
    
      const handleExchange = async (externalToken) => {
        try {
          const tokenResponse = await loginWithCustomTokenExchange({
            subject_token: externalToken,
            subject_token_type: 'urn:your-company:legacy-system-token',
            audience: 'https://api.example.com/',
            scope: 'openid profile email',
          });
    
          setTokens(tokenResponse);
          setError(null);
    
          console.log('Access Token:', tokenResponse.access_token);
          console.log('ID Token:', tokenResponse.id_token);
        } catch (e) {
          console.error('Token exchange failed:', e);
          setError(e.message);
        }
      };
    
      return (
        <div>
          <button onClick={() => handleExchange('your-external-token')}>
            Exchange Token
          </button>
          {tokens && <div>Token exchange successful!</div>}
          {error && <div>Error: {error}</div>}
        </div>
      );
    };
    
    export default TokenExchange;
  8. Configure Step-Up Authentication with interactiveErrorHandler

    main

    If you want to avoid building a custom MFA UI, you can use Step-Up Authentication. When a protected API requires MFA, the SDK can automatically open an Auth0 Universal Login popup. Once the user completes MFA in the popup, the SDK returns the access token transparently to your application.

    Requirements:

    • useRefreshTokens={true} must be set in Auth0Provider.
    • interactiveErrorHandler must be set to "popup".

    Warning: This only handles mfa_required errors. Other interactive errors are not intercepted.

    Error Handling: If the popup is blocked or cancelled, the SDK throws PopupOpenError, PopupCancelledError, or PopupTimeoutError.

    import { Auth0Provider } from '@auth0/auth0-react';
    
    function App() {
      return (
        <Auth0Provider
          domain="YOUR_AUTH0_DOMAIN"
          clientId="YOUR_AUTH0_CLIENT_ID"
          authorizationParams={{
            redirect_uri: window.location.origin,
            audience: 'https://api.example.com/',
          }}
          useRefreshTokens={true}
          interactiveErrorHandler="popup"
        >
          <MyApp />
        </Auth0Provider>
      );
    }
  9. Migrate from `advancedOptions.defaultScope` to `authorizationParams.scope`

    main

    The advancedOptions property and the defaultScope key have been removed in v2. To achieve the same effect, merge your previous defaultScope values into the main scope property within authorizationParams.

    // v2: Merge previous defaultScope and scope into one string
    <Auth0Provider
      authorizationParams={{
        scope: "email scope1"
      }}
    >
      <App />
    </Auth0Provider>
  10. Use DPoP with external APIs via fetchWithAuth()

    main

    When DPoP is enabled, tokens must be sent with an Authorization: DPoP <token> header instead of Bearer. While the useAuth() hook provides low-level methods like getDpopNonce(), setDpopNonce(), and generateDpopProof(), it is highly recommended to use fetchWithAuth() to handle nonce management, header generation, and retries automatically.

    To use fetchWithAuth() with DPoP, you must provide a dpopNonceId in the createFetcher() configuration to track nonces for specific requests.

    const { createFetcher } = useAuth0();
    
    const fetcher = createFetcher({
      dpopNonceId: 'my_api_request'
    });
    
    await fetcher.fetchWithAuth('https://api.example.com/foo', {
      method: 'GET',
      headers: { 'user-agent': 'My Client 1.0' }
    });
  11. Configure Connect Accounts for Token Vault

    main

    To use the Connect Accounts feature (allowing users to link third-party accounts like Google to access their Token Vault), the SDK must be configured with:

    1. An audience (the API Identifier for the resource server that will use the tokens).
    2. useRefreshTokens={true} and useMrrt={true} (to allow getting access tokens for the My Account API).
    3. useDpop={true} (required for the My Account API).
    <Auth0Provider
      domain="YOUR_AUTH0_DOMAIN"
      clientId="YOUR_AUTH0_CLIENT_ID"
      authorizationParams={{
        redirect_uri: window.location.origin,
        audience: '<AUTH0 API IDENTIFIER>'
      }}
      useRefreshTokens={true}
      useMrrt={true}
      useDpop={true}
    >
      <App />
    </Auth0Provider>