react-oidc-context

repository·main·Indexed 21 days ago

https://github.com/authts/react-oidc-context

A lightweight React authentication library built on top of oidc-client-ts. It provides React Context, Hooks, and Higher-Order Components to manage OpenID Connect (OIDC) and OAuth2 authentication flows in Single Page Applications, including features like the useAuth hook, withAuthenticationRequired for route protection, and useAutoSignin for automatic login.

Tokens
7.9K
Snippets
20
Records
27
Agent score
75%

What's inside react-oidc-context

  1. Access tokens outside of AuthProvider

    main

    If you need to access the access token in parts of your application that are not children of the AuthProvider (e.g., in a Redux slice or an external utility), you can retrieve the user from local storage.

    When using WebStorageStateStore, the user is stored with a key following the pattern: oidc.user:<authority>:<client_id>. You can use User.fromStorageString() from oidc-client-ts to reconstruct the user object.

    import { User } from "oidc-client-ts"
    
    function getUser() {
        // Replace <authority> and <client id> with your actual values
        const oidcStorage = localStorage.getItem(`oidc.user:<your authority>:<your client id>`)
        if (!oidcStorage) {
            return null;
        }
    
        return User.fromStorageString(oidcStorage);
    }
    
    // Usage in an async function
    const user = getUser();
    const token = user?.access_token;
    const response = await fetch("https://api.example.com/posts", {
        headers: {
            Authorization: `Bearer ${token}`,
        },
    });
  2. Implement automatic sign-in

    main

    There are two ways to implement automatic sign-in to re-establish sessions when a user returns to the app.

    Option 1: Manual implementation with hasAuthParams

    Use the hasAuthParams utility to check if the current URL contains authentication parameters. If not, and the user isn't authenticated, trigger signinRedirect.

    Option 2: The useAutoSignin hook

    Use the useAutoSignin hook inside the AuthProvider. This hook manages the sign-in logic automatically. You can specify the signinMethod (defaults to signinRedirect).

    // Using useAutoSignin
    import { useAutoSignin } from "react-oidc-context";
    
    function App() {
        const { isLoading, isAuthenticated, error } = useAutoSignin({
            signinMethod: "signinRedirect"
        });
    
        if (isLoading) return <div>Signing you in/out...</div>;
        if (error) return <div>An error occurred</div>;
        if (!isAuthenticated) return <div>Unable to log in</div>;
    
        return <div>Signed in successfully</div>;
    }
  3. Use the useAuth hook to access authentication state and methods

    main

    The useAuth hook is the primary way to access the authentication context within your functional components. It returns an object conforming to AuthContextProps, which provides both the current authentication state and methods to perform authentication actions.

    AuthState

    The AuthState object contains:

    • isAuthenticated: boolean indicating if a user is logged in.
    • isLoading: boolean indicating if the authentication state is currently being loaded.
    • user: User | null containing the current user information from oidc-client-ts.
    • error: ErrorContext | undefined containing error details if an authentication operation failed.
    • activeNavigator: A string indicating the current active authentication method (e.g., signinRedirect, signinPopup).

    AuthContextProps Methods

    You can call these methods directly from the object returned by useAuth:

    • signinRedirect(args?: SigninRedirectArgs): Initiates a redirect-based sign-in.
    • signinPopup(args?: SigninPopupArgs): Initiates a popup-based sign-in.
    • signinSilent(args?: SigninSilentArgs): Performs a silent sign-in.
    • signoutRedirect(args?: SignoutRedirectArgs): Initiates a redirect-based sign-out.
    • signoutPopup(args?: SignoutPopupArgs): Initiates a popup-based sign-out.
    • signoutSilent(args?: SignoutSilentArgs): Performs a silent sign-out.
    • signinResourceOwnerCredentials(args: SigninResourceOwnerCredentialsArgs): Performs sign-in using resource owner credentials.
    • revokeTokens(types?: RevokeTokensTypes): Revokes tokens.
    • removeUser(): Removes the current user.
    • clearStaleState(): Clears stale authentication state.
    • startSilentRenew(): Starts the silent token renewal process.
    • stopSilentRenew(): Stops the silent token renewal process.
    • querySessionStatus(args?: QuerySessionStatusArgs): Queries the session status.

    Note: events provides access to UserManagerEvents from oidc-client-ts.

    import { useAuth } from 'react-oidc-context';
    
    const MyComponent = () => {
      const auth = useAuth();
    
      if (auth.isLoading) {
        return <div>Loading...</div>;
      }
    
      if (auth.isAuthenticated) {
        return <button onClick={() => auth.signoutRedirect()}>Sign out</button>;
      } else {
        return <button onClick={() => auth.signinRedirect()}>Sign in</button>;
      }
    };
  4. Use the useAuth hook

    main

    The useAuth hook provides access to the authentication state and methods within functional components.

    State properties:

    • isLoading: Boolean indicating if authentication is in progress.
    • isAuthenticated: Boolean indicating if the user is logged in.
    • user: The current User object (from oidc-client-ts).
    • error: Error object if authentication fails.
    • activeNavigator: Indicates the current navigation state (e.g., signinSilent, signoutRedirect).

    Methods:

    • signinRedirect(): Initiates the redirect-based sign-in flow.
    • signOutRedirect(): Initiates the redirect-based sign-out flow.
    • removeUser(): Removes the current user.
    • signinSilent(): Performs a silent sign-in (token renewal).
    • events: Access to UserManagerEvents for imperative management.
    import React from "react";
    import { useAuth } from "react-oidc-context";
    
    function App() {
        const auth = useAuth();
    
        if (auth.isLoading) return <div>Loading...</div>;
    
        if (auth.isAuthenticated) {
            return (
            <div>
                Hello {auth.user?.profile.sub} 
                <button onClick={() => void auth.removeUser()}>Log out</button>
            </div>
            );
        }
    
        return <button onClick={() => void auth.signinRedirect()}>Log in</button>;
    }
  5. Use the useAutoSignin hook for automatic login

    main

    The useAutoSignin hook allows you to trigger an automatic sign-in process when a component mounts. This is useful for scenarios where you want to immediately redirect unauthenticated users to the identity provider.

    Usage

    Redirect-based sign-in

    To use a redirect-based sign-in, provide the signinMethod as signinRedirect:

    import { useAutoSignin } from 'react-oidc-context';
    
    const AutoSignInComponent = () => {
      useAutoSignin({
        signinMethod: 'signinRedirect',
        signinArgs: { /* SigninRedirectArgs */ }
      });
    
      return <div>Redirecting...</div>;
    };

    To use a popup-based sign-in, provide the signinMethod as signinPopup:

    import { useAutoSignin } from 'react-oidc-context';
    
    const AutoSignInComponent = () => {
      useAutoSignin({
        signinMethod: 'signinPopup',
        signinArgs: { /* SigninPopupArgs */ }
      });
    
      return <div>Opening popup...</div>;
    };
  6. Add authentication event listeners

    main

    You can listen to authentication events (like token expiration) by accessing auth.events via the useAuth hook. Note that many event listeners return a cleanup function that must be returned from useEffect to prevent memory leaks.

    import React from "react";
    import { useAuth } from "react-oidc-context";
    
    function App() {
        const auth = useAuth();
    
        React.useEffect(() => {
            // addAccessTokenExpiring returns a cleanup function
            return auth.events.addAccessTokenExpiring(() => {
                if (confirm("Session expiring. Stay signed in?")) {
                    auth.signinSilent();
                }
            });
        }, [auth.events, auth.signinSilent]);
    
        return <button onClick={() => void auth.signinRedirect()}>Log in</button>;
    }
  7. Protect a route with withAuthenticationRequired

    main

    Use the withAuthenticationRequired higher-order component to secure specific routes. If an unauthenticated user attempts to access the component, they will be automatically redirected to the login page. You can provide an OnRedirecting callback to render a fallback UI during the redirect process.

    import React from 'react';
    import { withAuthenticationRequired } from "react-oidc-context";
    
    const PrivateRoute = () => (<div>Private</div>);
    
    export default withAuthenticationRequired(PrivateRoute, {
      OnRedirecting: () => (<div>Redirecting to the login page...</div>)
    });
  8. Configure the AuthProvider

    main

    The AuthProvider component is the root provider that manages the authentication lifecycle. It can be configured in two ways: by providing a pre-configured UserManager instance or by providing UserManagerSettings directly.

    Configuration Options

    All configurations are passed via AuthProviderProps:

    • userManager (Optional): An existing instance of UserManager from oidc-client-ts.
    • signinArgs, signoutArgs, etc. (via UserManagerSettings): Standard settings for the underlying OIDC client.
    • onSigninCallback(user: User | undefined): A callback function triggered after a successful sign-in.
    • onSignoutCallback(resp: SignoutResponse | undefined): A callback function triggered after a sign-out.
    • onRemoveUser(): A callback triggered when a user is removed.
    • matchSignoutCallback(args: UserManagerSettings): A function to determine if the current URL matches the sign-out callback.
    • skipSigninCallback: A boolean to skip the sign-in callback processing.

    Usage Patterns

    If you provide a userManager, the provider uses that instance. If you do not provide a userManager, you must provide all required UserManagerSettings directly to the AuthProvider.

    import { AuthProvider } from 'react-oidc-context';
    
    const settings = {
      authority: 'https://auth.example.com',
      client_id: 'my-client-id',
      redirect_uri: 'https://myapp.com/callback',
      // ... other UserManagerSettings
    };
    
    function App() {
      return (
        <AuthProvider {...settings}>
          <MyRoutes />
        </AuthProvider>
      );
    }
  9. Protect components with withAuthenticationRequired

    main

    The withAuthenticationRequired higher-order component (HOC) is used to wrap components that should only be accessible to authenticated users. If a user is not authenticated, the HOC will handle the redirection to the sign-in page.

    Options

    withAuthenticationRequired accepts an optional WithAuthenticationRequiredProps object:

    • onBeforeSignin: A function that returns a Promise, called before the sign-in process begins.
    • OnRedirecting: A function that returns a JSX element to display while the user is being redirected to the identity provider.
    • signinRedirectArgs: Arguments passed to the signinRedirect method.

    Usage

    Wrap your protected component with the HOC:

    import { withAuthenticationRequired } from 'react-oidc-context';
    
    const ProtectedPage = () => <div>This is a secret page!</div>;
    
    export default withAuthenticationRequired(ProtectedPage, {
      onBeforeSignin: async () => {
        console.log('Preparing to sign in...');
      },
      OnRedirecting: () => <div>Redirecting to login...</div>
    });
  10. Use withAuth HOC for Class Components

    main

    To use authentication in React class components, wrap the component with the withAuth higher-order component. This injects an auth prop containing the same properties as the useAuth hook.

    import React from "react";
    import { withAuth } from "react-oidc-context";
    
    class Profile extends React.Component {
        render() {
            const auth = this.props.auth;
            return <div>Hello {auth.user?.profile.sub}</div>;
        }
    }
    
    export default withAuth(Profile);
  11. Configure useAutoSignin options

    main

    The useAutoSignin hook accepts an optional configuration object to specify the sign-in method and associated arguments.

    signinMethod

    Determines how the sign-in flow is initiated. Supported values:

    • "signinRedirect" (Default): Uses the redirect method.
    • "signinPopup": Uses the popup window method.

    signinArgs

    Provides additional configuration for the chosen sign-in method. The shape of this object depends on the signinMethod selected:

    • If signinMethod is "signinRedirect", use SigninRedirectArgs (e.g., redirect_uri, extraQueryParams).
    • If signinMethod is "signinPopup", use SigninPopupArgs (e.g., popup window features).