npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

esi-react-aad-msal

v2.2.4-fix.1

Published

A react component that integrates with Azure AD (v2, MSAL).

Downloads

9

Readme

React AAD MSAL

A library of components to easily integrate the Microsoft Authentication Library with Azure Active Directory in your React app quickly and reliably. The library focuses on flexibility, providing functionality to login, logout, and fetch the user details while maintaining access to the underlying MSAL library for advanced use.

:exclamation: This library is not affiliated with the Identity team at Microsoft. It was developed as a tool for the Open Source community to use and contribute to as they see fit.

:memo: Table of contents

:tada: Features

:white_check_mark: Login/logout with AzureAD component
:white_check_mark: Callback functions for login success, logout success, and user info changed
:white_check_mark: withAuthentication higher order component for protecting components, routes, or the whole app
:white_check_mark: Function as Child Component pattern (FaCC) to pass authentication data and login/logout functions to children components
:white_check_mark: Redux integration for storing authentication status, user info, tokens, etc
:white_check_mark: Automatic renewal of IdTokens, and optional function to get a fresh token at any point
:white_check_mark: Easily fetch a fresh Access Token from cache (or refresh it) before calling API endpoints

:checkered_flag: Getting Started

Prerequisites

Installation

Via NPM:

npm install react-aad-msal msal --save

Creating the Provider

Before beginning it is required to configure an instance of the MsalAuthProvider and give it three parameters:

| Parameters | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | config | Instance of a Msal.Configuration object to configure the underlying provider. The documentation for all the options can be found in the configuration options doc | | parameters | Instance of the Msal.AuthenticationParameters configuration to identify how the authentication process should function. This object includes the scopes values. You can see possible values for scopes here | | options | [Optional] The options are defined by the IMsalAuthProviderConfig interface. This contains settings that describe how the authentication provider should handle certain authentication processes. |

The MsalAuthProvider is meant to be a singleton. There are known implications when multiple instances of MSAL are running at the same time. The recommended approach is to instantiate the MsalAuthProvider in a separate file and import it when needed.

// authProvider.js
import { MsalAuthProvider, LoginType } from 'esi-react-aad-msal';

const config = {
  auth: {
    authority: 'https://login.microsoftonline.com/common',
    clientId: '<YOUR APPLICATION ID>',
    redirectUri: '<OPTIONAL REDIRECT URI>'
  },
  cache: {
    cacheLocation: "localStorage",
    storeAuthStateInCookie: true
  }
};

const authenticationParameters = {
  scopes: [
    '<property (i.e. user.read)>',
    'https://<your-tenant-name>.onmicrosoft.com/<your-application-name>/<scope (i.e. demo.read)>'
  ]
}

const options = {
  loginType: LoginType.Popup,
  tokenRefreshUri: window.location.origin + '/auth.html'
}

export const authProvider = new MsalAuthProvider(config, authenticationParameters, options)

Now you can import the authProvider and use it in combination with one of the authentication components.

// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { AzureAD } from 'esi-react-aad-msal';

import App from './App';
import { authProvider } from './authProvider';

ReactDOM.render(
  <AzureAD provider={authProvider} forceLogin={true}>
    <App />
  </AzureAD>,
  document.getElementById('root'),
);

Configuration Options

The options that get passed to the MsalAuthProvider are defined by the MSAL library, and are described in more detail in the configuration options documentation.

Below is the total set of configurable options that are supported currently in the config.

  // Configuration Object
  export type Configuration = {
    auth: AuthOptions,
    cache?: CacheOptions,
    system?: SystemOptions
  };

  // Protocol Support
  export type AuthOptions = {
    clientId: string;
    authority?: string;
    validateAuthority?: boolean;
    redirectUri?: string | (() => string);
    postLogoutRedirectUri?: string | (() => string);
    navigateToLoginRequestUrl?: boolean;
  };

  // Cache Support
  export type CacheOptions = {
    cacheLocation?: CacheLocation;
    storeAuthStateInCookie?: boolean;
  };

  // Library support
  export type SystemOptions = {
    logger?: Logger;
    loadFrameTimeout?: number;
    tokenRenewalOffsetSeconds?: number;
    navigateFrameWait?: number;
  };

For more information on MSAL config options refer to the MSAL configuration options documentation.

Authentication Parameters

When instantiating an instance of the MsalAuthProvider the authentication parameters passed will become the default parameters used when authenticating and fetching or refreshing tokens. It is possible to change the default parameters later by executing the setAuthenticationParameters() method on the MsalAuthProvider.

The set of options that are supported for the Msal.AuthenticationParameters class can be found below as they are defined in the MSAL library.

  export type AuthenticationParameters = {
    scopes?: Array<string>;
    extraScopesToConsent?: Array<string>;
    prompt?: string;
    extraQueryParameters?: {[key: string]: string};
    claimsRequest?: string;
    authority?: string;
    state?: string;
    correlationId?: string;
    account?: Account;
    sid?: string;
    loginHint?: string;
  };

Options

The options parameter defines settings related to how the authentication provider processes authentication operations.

const options = {
  // The default login type is Popup
  loginType: LoginType.Popup,
  // A blank html page that MSAL can load in an iframe to refresh the token
  // The default setting for this parameter is `window.location.origin`
  tokenRefreshUri: window.location.origin + '/auth.html'
}

LoginType is an enum with two options for Popup or Redirect authentication. This parameter is optional and will default to Popup if not provided. The tokenRefreshUri allows you to set a separate page to load only when tokens are being refreshed. When MSAL attempts to refresh a token, it will reload the page in an iframe. This option allows you to inform MSAL of a specific page it can load in the iframe. It is best practice to use a blank HTML file so as to prevent all your site scripts and contents from loading multiple times.

At any time after instantiating the MsalAuthProvider the login type can be changed using the setProviderOptions() method. You may also retrieve the current options using the getProviderOptions() method.

:package: Authentication Components

The library provides multiple components to integrate Azure AD authentication into your application and each component has various use cases. The are also plans for additional components, documented in the project Roadmap.

AzureAD Component

The AzureAD component is the primary method to add authentication to your application. When the component is loaded it internally uses MSAL to check the cache and determine the current authentication state. The users authentication status determines how the component will render the children.

  1. If the children is an element, it will only be rendered when the AzureAD detects an authenticated user.
  2. If the children is a function, then it will always be executed with the following argument:
    {
      login, // login function
      logout, // logout function
      authenticationState, // the current authentication state
      error, // any error that occured during the login process
      accountInfo, // account info of the authenticated user
    }

The AzureAD component will check that the IdToken is not expired before determining that the user is authenticated. If the token has expired, it will attempt to renew it silently. If a valid token is maintained it will be sure there is an active Access Token available, otherwise it will refresh silently. If either of the tokens cannot be refreshed without user interaction, the user will be prompted to signin again.

import { AzureAD, AuthenticationState, AuthenticationState } from 'esi-react-aad-msal';

// Import the provider created in a different file
import { authProvider } from './authProvider';

// Only authenticated users can see the span, unauthenticated users will see nothing
<AzureAD provider={authProvider}>
  <span>Only authenticated users can see me.</span>
</AzureAD>

// If the user is not authenticated, login will be initiated and they will see the span when done
<AzureAD provider={authProvider} forceLogin={true}>
  <span>Only authenticated users can see me.</span>
</AzureAD>

// Using a function inside the component will give you control of what to show for each state
<AzureAD provider={authProvider} forceLogin={true}>
  {
    ({login, logout, authenticationState, error, accountInfo}) => {
      switch (authenticationState) {
        case AuthenticationState.Authenticated:
          return (
            <p>
              <span>Welcome, {accountInfo.account.name}!</span>
              <button onClick={logout}>Logout</button>
            </p>
          );
        case AuthenticationState.Unauthenticated:
          return (
            <div>
              {error && <p><span>An error occured during authentication, please try again!</span></p>}
              <p>
                <span>Hey stranger, you look new!</span>
                <button onClick={login}>Login</button>
              </p>
            </div>
          );
        case AuthenticationState.InProgress:
          return (<p>Authenticating...</p>);
      }
    }
  }
</AzureAD>

The following props are available to the AzureAD component.

| AzureAD Props | Description | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | provider | An MsalAuthProvider instance containing configuration values for your Azure AD instance. See [Creating the Provider](#Creating the Provider) for details. | | authenticatedFunction | :warning: [Deprecated] [Optional] A user defined callback function for the AzureAD component to consume. This function receives the AzureAD components logout function which you can use to trigger a logout. The return value will be rendered by the AzureAD component. If no return value is provided, the children of the AzureAD component will be rendered instead. | | unauthenticatedFunction | :warning: [Deprecated] [Optional] A user defined callback function for the AzureAD component to consume. This function receives the AzureAD components login function which you can then use to trigger a login. The return value will be rendered by the AzureAD component. | | accountInfoCallback | :warning: [Deprecated] [Optional] A user defined callback function for the AzureAD component to consume. The AzureAD component will call this function when login is complete to pass back the user info as an instance of IAccountInfo. In addition to the tokens, the account info includes the Msal.Account | | reduxStore | [Optional] You can provide a redux store which the component will dispatch actions to when changes occur. You can find the list of all actions defined in the AuthenticationActions enum. | | forceLogin | [Optional] A boolean that identifies whether the login process should be invoked immediately if the current user is unauthenticated. Defaults to false. |

Higher Order Component

Sometimes it's easier to utilize a Higher Order Component (HoC) to lock down an app or page component with authentication. This can be accomplished using the withAuthentication component which acts as a wrapper for the AzureAD component.

import { withAuthentication } from 'esi-react-aad-msal';

// The instance of MsalAuthProvider defined in a separate file
import { authProvider } from './authProvider.js';

// The App component wrapped in the withAuthentication() HoC
export default withAuthentication(App, {
 provider: authProvider,
 reduxStore: store
});

The first parameter is the component that requires authentication before being mounted. The second parameter is an object containing the props to be passed into the AzureAD component. With this approach the forceLogin prop will default to true. This is a good way to protect routes or quickly require authentication for your entire App in several lines.

:mortar_board: Advanced Topics

Getting Tokens for API Requests

The library components will manage authenticating the user without you needing to think about tokens. But there are scenarios where a fresh token will be needed to communicate with a service or to decode the token to examine the claims. The library exposes methods for retrieving active IdTokens and Access Tokens.

For more advanced scenarios where you need specific control over error handling when a token fails to renew you can always access the MSAL API methods and renew a token manually as described in the MSAL token renewal pattern documentation.

Refreshing Access Tokens

To get a fresh and valid Access Token to pass to an API you can call the getAccessToken() on the MsalAuthProvider instance. This function will asynchronously attempt to retrieve the token from the cache. If the cached token has expired it will automatically attempt to refresh it. In some scenarios the token refresh will fail and the user will be required to authenticate again before a fresh token is provided. The method will handle these scenarios automatically.

The getAccessToken() returns an instance of the AccessTokenResponse class. The following snippet is an example of how you might use the function before calling an API endpoint.

// authProvider.js
import { MsalAuthProvider, LoginType } from 'esi-react-aad-msal';
export const authProvider = new MsalAuthProvider(
  {
    /* config */
  },
  {
    /* parameters */
  },
  LoginType.Popup,
);

// api.js
import { authProvider } from './authProvider';

const request = async url => {
  const token = await authProvider.getAccessToken();

  return fetch(url, {
    method: 'GET',
    headers: {
      Authorization: 'Bearer ' + token.accessToken,
      'Content-Type': 'application/json',
    },
  });
};

Renewing IdTokens

To get a fresh and valid IdToken you can call the getIdToken() on the MsalAuthProvider instance. This function will asynchronously attempt to retrieve the token from the cache. If the cached token has expired it will automatically attempt to renew it. In some scenarios the token renewal will fail and the user will be required to authenticate again before a new token is provided. The method will handle these scenarios automatically.

The getIdToken() returns an instance of the IdTokenResponse class. The following snippet is an example of how you might use the function to retrieve a valid IdToken.

// authProvider.js
import { MsalAuthProvider, LoginType } from 'esi-react-aad-msal';
export const authProvider = new MsalAuthProvider(
  {
    /* config */
  },
  {
    /* parameters */
  },
  LoginType.Popup,
);

// consumer.js
import { authProvider } from './authProvider';
const token = await authProvider.getIdToken();
const idToken = token.idToken.rawIdToken;

Integrating with a Redux Store

The AzureAD component optionally accepts a reduxStore prop. On successful login and after an Access Token has been acquired, an action of type AAD_LOGIN_SUCCESS will be dispatch to the provided store containing the token and user information returned from Active Directory. It does the same for logout events, but the action will not contain a payload.

Import your store into the file rendering the AzureAD component and pass it as a prop:

// authProvider.js
import { MsalAuthProvider, LoginType } from 'esi-react-aad-msal';
export const authProvider = new MsalAuthProvider(
  {
    /* config */
  },
  {
    /* parameters */
  },
  LoginType.Popup,
);

// index.js
import { authProvider } from './authProvider';
import { store } from './reduxStore.js';

// ...

ReactDOM.render(
  <AzureAD provider={authProvider} reduxStore={store}>
    <App />
  </AzureAD>,
  document.getElementById('root'),
);

Add a case to handle AAD_LOGIN_SUCCESS and AAD_LOGOUT_SUCCESS actions in a reducer file:

const initialState = {
  aadResponse: null,
};

const sampleReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'AAD_LOGIN_SUCCESS':
      return { ...state, aadResponse: action.payload };
    case 'AAD_LOGOUT_SUCCESS':
      return { ...state, aadResponse: null };
    default:
      return state;
  }
};

In addition to login and logout actions, the MsalAuthProvider will dispatch other actions for for various state changes. The full list can be found in the actions.ts file and in the table below. An example of a fully implemented sample reducer can be found in the sample project.

| Action Type | Payload | Description | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | AAD_INITIALIZING | None | Dispatched when the MsalAuthProvider is instantiated and begins checking the cache to determine if the user is authenticated | | AAD_INITIALIZED | None | Signifies that the MsalAuthProvider has successfully determined the authentication status of the user after being instantiated. It is safest not to use any state until initialization has completed | | AAD_AUTHENTICATED_STATE_CHANGED | AuthenticationState | Dispatched whenever the user's authentication status changes | | AAD_ACQUIRED_ID_TOKEN_SUCCESS | IdTokenResponse | Identifies that the IdToken has been retrieved or renewed successfully | | AAD_ACQUIRED_ID_TOKEN_ERROR | Msal.AuthError | Dispatched when an error occurred while attempting to retrieve or renew the IdToken | | AAD_ACQUIRED_ACCESS_TOKEN_SUCCESS | AccessTokenResponse | Identifies that the Access Token has been retrieved or refreshed successfully | | AAD_ACQUIRED_ACCESS_TOKEN_ERROR | Msal.AuthError | Dispatched when an error occurred while attempting to retrieve or refresh the Access Token | | AAD_LOGIN_SUCCESS | IAccountInfo | Dispatched when the user has been authenticated and a valid Access Token has been acquired | | AAD_LOGIN_FAILED | None | Dispatched when the authentication process fails | | AAD_LOGIN_ERROR | Msal.AuthError | Identifies that an error occurred while login was in process | | AAD_LOGOUT_SUCCESS | None | Dispatched when the user has successfully logged out on the client side |

Accessing the MSAL API

While this wrapper attempts to provide a full-featured means of authenticating with AzureAD, for advanced cases you may want to access the underlying MSAL API. The MsalAuthProvider extends the MSAL UserAgentApplication class and will give you access to all the functions available, in addition to implementing new methods used by the library components.

const authProvider = new MsalAuthProvider(config, authenticationParameters);
// authProvider provides access to MSAL features

It is not recommended to use this method if it can be avoided, since operations executed via MSAL may not reflect in the wrapper.

:cd: Sample application

If you'd like to see a sample application running please see the sample application built with Create React App.

The project can be built with the following steps:

  1. git clone https://github.com/syncweek-react-aad/react-aad.git
  2. cd ./react-aad
  3. Build the react-aad library:
    • npm install
    • npm run build
  4. Run the sample project:
    • npm start

Be sure to modify the authProvider.js configuration to specify your own ClientID and Authority.

:calendar: Roadmap

While the library is ready for use there is still plenty of ongoing work. The following is a list of a few of the improvements under consideration.

:white_medium_small_square: Rewrite the sample app to use hooks and simplify the logic.
:white_medium_small_square: Add a useAuthentication() hook to the library.
:white_medium_small_square: Replace the AzureAD render props with event handlers.
:white_medium_small_square: Add Context API provider.
:white_medium_small_square: Separate MSAL and Redux dependencies as peerDependencies
:white_medium_small_square: Migrate to a build system such as Webpack, or Rollup.
:white_medium_small_square: Add samples for consuming a Web API.
:white_medium_small_square: Improve unit test coverage across the library.
:white_medium_small_square: Maintain feature parity between the official MSAL Angular library after it undergoes its planned upgrade.

:books: Resources

The following resources may be helpful and provide further insight. If you've written a blog post, tutorial, or article feel free to create an issue so we can include it.

:trophy: Contributers

This library is built with :heart: by members of the open source community. To become a contributer, please see the contribution guidelines.