react-aad icon indicating copy to clipboard operation
react-aad copied to clipboard

getAccessToken, infinitely calls within Azure

Open ghost opened this issue 5 years ago • 4 comments
trafficstars

Library versions

  • react-aad-msal: 2.3.2
  • msal: 1.2.1

Describe the bug When calling authprovider.getAccessToken() it infinitely to calls the cache and continues to unmount/remount the app

Expected behavior To get a new access token once, thus being able to call the api once.

To Reproduce Steps to reproduce the behavior:

  1. Get Projects is invoked in a useffect with empty dependancy array
  2. In console, Token is already in cache for [scope] Screenshot 2020-04-01 at 15 59 48

Desktop (please complete the following information):

  • OS: Mac Mojave 10.16.6
  • Browser: Chrome 80.0.3987.149

authProvider,js

// Auth Provider
import { MsalAuthProvider, LoginType } from 'react-aad-msal';
import { Logger, LogLevel } from 'msal';

const isIE = () => {
  const ua = window.navigator.userAgent;
  const msie = ua.indexOf('MSIE ') > -1;
  const msie11 = ua.indexOf('Trident/') > -1;

  // If you as a developer are testing using Edge InPrivate mode, please add "isEdge" to the if check
  // const isEdge = ua.indexOf("Edge/") > -1;

  return msie || msie11;
};

// Msal Configurations
const config = {
  auth: {
    clientId: '********',
    authority:
      'https://login.microsoftonline.com/*******/',
    validateAuthority: true,
    navigateToLoginRequestUrl: false,
    redirectUri: window.location.origin + '/auth.html',
    postLogoutRedirectUri: window.location.origin,
  },
  cache: {
    cacheLocation: 'localStorage',
    storeAuthStateInCookie: isIE(),
  },
  system: {
    logger: new Logger(
      (logLevel, message, containsPii) => {
        console.log('[MSAL]', message);
      },
      {
        level: LogLevel.Verbose,
        piiLoggingEnabled: false,
      }
    ),
  },
};

// Authentication Parameters
const authenticationParameters = {
  scopes: ['*****', '*****'],
};

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

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

api,js

const getToken = async () => {
  const token = await authProvider.getAccessToken({
    scopes: ['*******'],
  });
  console.log('token being called');
  return {
    headers: {
      Authorization: 'Bearer ' + token.accessToken,
    },
  };
};

export const fetchProjects = async () => {
  const headers = await getToken();
  const {
    data: { projects },
  } = await axios.get(`${BASE_URL}/projects`, headers);
  return projects;
};

App Wrapped withRoot.js

function withRoot(Component) {
  function WithRoot(props) {
    return (
      <ThemeProvider theme={theme}>
        <CssBaseline />
        <AzureAD provider={authProvider}>
          {({ login, logout, authenticationState, error }) => {
            return (
              <Router>
                <Component
                  {...props}
                  authenticationState={authenticationState}
                  login={login}
                  logout={logout}
                />
              </Router>
            );
          }}
        </AzureAD>
      </ThemeProvider>
    );
  }

  return WithRoot;
}

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './containers/app';
import withRoot from './containers/app/withRoot';

const WrappedApp = withRoot(App);

ReactDOM.render(<WrappedApp />, document.getElementById('root'));

Home.js

import { useState, useEffect } from 'react';
import { getAllProjects } from '../../../api/graphql-api';
import { fetchProject } from '../../../api/ddb-api';

export default (limit, filter) => {
  const [projects, setProjects] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(false);

  useEffect(() => {
    const getProjects = () => {
      console.log('here ddb invoke');
      fetchProject(5)
        .then(res => {
          setProjects(res);
          setLoading(false);
        })
        .catch(err => console.log('DDB ERR!!!', err));
      setLoading(false);
    };
    getProjects();
    console.log('->>>>> use effect called');
  },[]);
  return { projects, loading, error };
};

ghost avatar Apr 01 '20 15:04 ghost

Had the same problem. Here is the cause and a solution: https://github.com/syncweek-react-aad/react-aad/issues/195#issuecomment-577014503

mardomza avatar Apr 10 '20 19:04 mardomza

included the auth.html in folder, and still getting the same errors, also not wanting to store the token as a global key

ghost avatar Apr 10 '20 19:04 ghost

I am facing the same problem, auth.html is included in public folder, there is no error occuring but every getAccessToken call make a new request on azure to get a token, this is not the properly behavior, according to the docs, "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".

luanbon avatar Jun 07 '20 04:06 luanbon

After a little more investigation, I found that this issue only repros when I have 'openid' or 'profile' in my token request scopes. If the scopes property is just https://<App URI>/user, I see the expected behavior of the cached token being reused. Even if I include multiple scopes in the request, the behavior is as expected if the scopes are just app scopes (rather than OIDC items like openid or profile).

It's not clear to me why having those scopes changes this behavior, but it at least narrows down what's going on.

luanbon avatar Jun 07 '20 05:06 luanbon