DEV Community

Cover image for Apollo Client Authentication with MSAL
Othmane Sabih
Othmane Sabih

Posted on

Apollo Client Authentication with MSAL

Managing authentication and the overhead that comes with it can be a hassle in terms of maintenance and security. That's why, it is easier to use an identity provider such as Google, Microsoft and others, to allow users to log into your app and navigate to protected routes.

In my company, we write frontends in React, and use Apollo Client for state management and to communicate with our GraphQL APIs, so we looked for a way to leverage MSAL (Microsoft Authentication Library) to acquire tokens from the Microsoft Identity Platform.

MSAL uses a refresh token to renew the access token that Apollo Client will send with requests. So it has a silent acquire mechanism to try to fetch access token using the cached refresh token, if it fails, it throws an exception, which means you will need user interaction with the Microsoft's login frame to fetch another access token once the user logs in again.

Without further ado, let's proceed with the code.
We are going to need the following packages in a react project.

yarn add @apollo/client @azure/msal-browser @azure/msal-react

src/
┣ app/
┃ ┣ hooks/
┃ ┃ ┗ useQueryUser.js
┃ ┣ services/
┃ ┃ ┣ Apollo/
┃ ┃ ┃ ┗ index.js
┃ ┃ ┗ Auth/
┃ ┃ ┣ auth-config.js
┃ ┃ ┗ index.js
┃ ┣ view/
┃ ┃ ┗ index.js
┃ ┗ index.js
┣ shared/
┃ ┗ helpers/
┃ ┗ Addhocs/
┃ ┃ ┗ index.js
┣ App.test.js
┣ index.css
┣ index.js
┗ setupTests.js

I will put a link for the github repo of the project, but for now let's take a look at the function that will acquire the token.

After instantiating MSAL and loading the configuration required, we can use hooks to call the library's functions.

First, the AsyncTokenLookup function will check if there are any cached users, if it finds one, it will try to acquire the token silently using acquireTokenSilent from MSAL.
If the process fails, we can prompt the user's interaction by initiating a redirect to Microsoft's login endpoint using acquireTokenRedirect or opening a popup using acquireTokenPopup.

    const AsyncTokenLookup = async () => {
      const accounts = await instance.getAllAccounts();

      const account = get(accounts, "[0]");
      if (account && inProgress === "none") {
        try {
          const result = await instance.acquireTokenSilent({
            ...loginSilentRequest,
            account,
          });
          return result.accessToken;
        } catch (err) {
          if (err instanceof InteractionRequiredAuthError) {
            // fallback to interaction when silent call fails
            return instance.acquireTokenRedirect(loginRequest);
          }
        }
      } else if (!account && inProgress === "none") {
        return instance.acquireTokenRedirect(loginRequest);
      }
    };
Enter fullscreen mode Exit fullscreen mode

Otherwise, if the silent acquiring succeeds, we return the access token to be sent by Apollo in the authorization header.

For that, we use the setContext function present in the @apollo/client package in order to inject the token in the Authorization header.

    const withToken = setContext(async (_, { headers }) => {
      const token = await AsyncTokenLookup();
      return {
        headers: {
          ...headers,
          Authorization: token ? `Bearer ${token}` : null,
        },
      };
    });
Enter fullscreen mode Exit fullscreen mode

Then, we will create a new Apollo client chaining httpLink and withToken.

    const httpLink = createHttpLink({
      uri: process.env.REACT_APP_BACKEND_URI,
    });

    const client = new ApolloClient({
      link: from([withToken, httpLink]),
      cache: new InMemoryCache(),
    });
Enter fullscreen mode Exit fullscreen mode

Note that in this example, we are only enabling accounts in one organizational directory only, and not personal Microsoft accounts.

Here is a link to the github repo:

GitHub logo othpwn / apollo-client-msal-boilerplate

Boilerplate to get you started with Apollo Client authentication using MSAL

apollo-client-msal-boilerplate

Boilerplate to get you started with Apollo Client authentication using MSAL

Top comments (1)

Collapse
 
bartlomiejborzucki profile image
Bartłomiej Borzucki

Does this solution work with React 18?