Microsoft-authentication-library-for-js: AADSTS50058: A silent sign-in request was sent but no user is signed in.

Created on 2 Jul 2020  Â·  15Comments  Â·  Source: AzureAD/microsoft-authentication-library-for-js

Please follow the issue template below. Failure to do so will result in a delay in answering your question.

Library

Important: Please fill in your exact version number above, e.g. [email protected].

Framework

  • React

Description

Getting an access token throws the following error in IE11, Edge and Chrome Incognito. Tried multiple variations of config and cache settings. It looks like the id_token isn't being stored correctly before the access token is being requested or the iframe isn't receiving the cookie. The constructor calls initialising which might be asynchronous creating a race condition when the #idtoken= is returned but before the acquireTokenSilent method is called.

Error Message

client.js?7ed9:45 InteractionRequiredAuthError: AADSTS50058: A silent sign-in request was sent but no user is signed in. The cookies used to represent the user's session were not sent in the request to Azure AD. This can happen if the user is using Internet Explorer or Edge, and the web app sending the silent sign-in request is in different IE security zone than the Azure AD endpoint (login.microsoftonline.com).

Security

  • [x] Is this issue security related?

MSAL Configuration

{
    auth: {
      scopes,
      clientId,
      authority,
      validateAuthority: true,
      postLogoutRedirectUri: window.location.origin,
      redirectUri: `${window.location.origin}`,
      navigateToLoginRequestUrl: true,
    },
    cache: {
      cacheLocation: 'sessionStorage',
      storeAuthStateInCookie: true,
    },
  }

Reproduction steps

auth.loginRedirect({ scopes: ['openid', 'profile'] });
auth.acquireTokenSilent({ scopes: [`${clientId}/.default`, 'offline_access'] })

Expected behavior

Returns an access token but throws error.

Browsers/Environment

  • [x] Chrome
  • [ ] Firefox
  • [x] Edge
  • [x] Safari
  • [x] IE
  • [ ] Other (Please add browser name here)
[email protected] no-issue-activity question

All 15 comments

Hi @sidhuko, please call the getAccount API before calling acquireTokenSilent. In addition, when receive an interaction required error, you should fall back to interactive call, either acquireTokenRedirect or acquireTokenPopup.
Can you also provide a code snippet showing any other code relevant to this issue?

I've implemented all this and it just keeps requesting an access_token, returning it on the URL, then throwing the error when it is called again. It is something internal about storing the user information in the cache or storage which is then not available in Chrome Incognito, Edge or IE11. This library don't really have good tests or a sample for a modern react application which demonstrates how to use it properly but I've spent enough time on this implementation to try all sorts of configurations. It was working before the other week. You seem to have a Github release for nearly two weeks ago but the package released on npm is from one month ago. Did you manage to overwrite a release on NPM and break a published version with new code?

It is that or a change in the browser security settings or how your AD service provisions tokens which this library sees as no longer valid. I seem to be missing a sid on the token now.

// useAuth.ts

import { useState } from 'react';
import { UserAgentApplication } from 'msal';

export function useAuth({ clientId, authority }) {
  const scopes = [`${clientId}/.default`, 'offline_access'];

  const config = {
    auth: {
      scopes,
      clientId,
      authority,
      validateAuthority: true,
      postLogoutRedirectUri: window.location.origin,
      redirectUri: `${window.location.origin}`,
      navigateToLoginRequestUrl: true,
    },
    cache: {
      cacheLocation: 'localStorage',
      storeAuthStateInCookie: true,
    },
  };

  const [auth] = useState(new UserAgentApplication(config));

  return { auth, config, scopes };
}
// client.js
import { HttpLink } from 'apollo-link-http';
import { ApolloClient } from 'apollo-client';
import { ApolloLink } from 'apollo-link';
import { onError } from 'apollo-link-error';
import {
  InMemoryCache,
  IntrospectionFragmentMatcher,
} from 'apollo-cache-inmemory';
import introspectionQueryResultData from '@hks/queries';

import { setContext } from 'apollo-link-context';

import { history } from './history';
import { GRAPHQL_GATEWAY } from './constants';

export const client = ({ auth, scopes }) => {
  // Ignore subsequent, machine-gunned error responses
  let previousErrorTime = 0;

  const errorLink = onError(({ networkError }) => {
    const currentErrorTime = new Date().getTime();
    if (networkError && currentErrorTime - previousErrorTime > 500) {
      const params = new URLSearchParams(history.location.search);
      // `?networkError=true` is picked up in the <App /> component
      params.set('networkError', true);
      history.push({
        pathname: history.location.pathname,
        search: params.toString(),
      });
    }
    previousErrorTime = currentErrorTime;
  });

  const authLink = setContext(async (_, { headers }) => {
    try {
      console.log('acquireTokenSilent');
      const { accessToken } = await auth.acquireTokenSilent({
        scopes,
      });

      return {
        headers: {
          ...headers,
          authorization: accessToken ? `Bearer ${accessToken}` : '',
        },
      };
    } catch (error) {
      // eslint-disable-next-line no-console
      console.error(error);
      console.log('acquireTokenRedirect');
      const { accessToken } = await auth.acquireTokenRedirect({
        scopes,
      });

      return {
        headers: {
          ...headers,
          authorization: accessToken ? `Bearer ${accessToken}` : '',
        },
      };
    }
  });

  const httpLink = new HttpLink({
    uri: GRAPHQL_GATEWAY,
  });

  const link = ApolloLink.from([errorLink, authLink.concat(httpLink)]);

  return new ApolloClient({
    link,
    cache: new InMemoryCache({
      fragmentMatcher: new IntrospectionFragmentMatcher({
        introspectionQueryResultData,
      }),
    }),
    name: 'portfolio',
    version: '0.0.1',
    queryDeduplication: false,
    defaultOptions: {
      watchQuery: {
        fetchPolicy: 'cache-and-network',
      },
    },
  });
};
// Root.jsx
import React from 'react';
import { hot } from 'react-hot-loader/root';

import { Router, Route, Switch } from 'react-router-dom';

import {
  DataProvider,
  AuthProvider,
  AuthorizeProvider,
  FrameworkProvider,
} from '@hks/framework';

import { client } from './client';
import { history } from './history';
import { FEATURES, AAD_CLIENT_ID, AAD_AUTHORITY } from './constants';
import { App } from './components/App/App';

export const Root = hot(() => (
  <FrameworkProvider history={history} features={FEATURES}>
    <AuthProvider clientId={AAD_CLIENT_ID} authority={AAD_AUTHORITY}>
      <Router history={history}>
        <Switch>
          <Route>
            <DataProvider client={client}>
              <App />
            </DataProvider>
          </Route>
        </Switch>
      </Router>
    </AuthProvider>
  </FrameworkProvider>
));
// AuthProvider.js
import React, { useEffect, useState } from 'react';

import { useAuth } from '../hooks/useAuth';
import { AuthContext } from '../contexts/AuthContext';
import { Flex } from '../components/Flex/Flex';
import { Loading } from '../components/Loading/Loading';

export const AuthProvider = ({ children, clientId, authority }) => {
  const { auth, config, scopes } = useAuth({ clientId, authority });
  const isLoginInProgress = auth.getLoginInProgress();
  const [user] = useState(auth.getAccount());

  if (!user && !isLoginInProgress) {
    return (
      <>
        {(() => {
          auth.loginRedirect({ scopes: ['openid', 'profile'] });
        })()}
      </>
    );
  }

  console.log(
    'user',
    user,
    isLoginInProgress,
    !user || isLoginInProgress ? 'loading' : 'shown'
  );

  return (
    <AuthContext.Provider
      value={{ auth, config, scopes, user, isLoading: isLoginInProgress }}
    >
      {!user || isLoginInProgress ? (
        <Flex flex="1 1" justifyContent="center" height="100%">
          <Loading />
        </Flex>
      ) : (
        <>{children}</>
      )}
    </AuthContext.Provider>
  );
};
// DataProvider.jsx

import React, { useContext } from 'react';
import { ApolloProvider } from '@apollo/react-hooks';

import { AuthContext } from '../contexts/AuthContext';

export const DataProvider = ({ children, client }) => {
  const { auth, scopes } = useContext(AuthContext);
  return (
    <ApolloProvider client={client({ auth, scopes })}>
      {children}
    </ApolloProvider>
  );
};

Just to confirm it works fine in normal Chrome but its most other browsers. Safari, Chrome (Incognito), Edge and IE11 which are throwing the error after login. The library itself creates a race condition by breaking the Single Responsibility Design principle and initialising in the constructor. That logic takes the token from url, changes the url and adds it into cache but maybe not synchronously.

Tested in 1.3.1 - does not work, same issue
Tested in 1.3.0 - does not work, same issue

@sidhuko
had this issue recently. Check in browser settings if your browser is blocking third party cookies in incognito. Basically for us every time we logged in nothing was stored and so kept tying to relog in on redirect. Changing the browser setting for incognito mode solved it

I don't think changing the browser setting is an acceptable solution for
all users.

On Thu, 9 Jul 2020 at 12:26, Jedd Shneier notifications@github.com wrote:

@sidhuko https://github.com/sidhuko
had this issue recently. Check in browser settings if your browser is
blocking third party cookies in incognito. basically for us everything we
logged in nothing was stored and so kept tying to relog in on redirect.
Changing the browser setting for incognito mode solved it

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/1880#issuecomment-656281667,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAVFBWICAOLJZN2RLEFIY3LR2YDTXANCNFSM4OPFBXCA
.

@sidhuko The reason why you are receiving this error is likely because MSAL is making a network request to get an access token, however, third-party cookies (which are required for silent requests) are being blocked by your browser settings. If you are receiving this error after calling acquireTokenSilent after you have just completed an interactive request (acquireTokenRedirect or acquireTokenPopup), it means that the call to acquireTokenSilent resulted in a cache miss, which, in this scenario, is often due to improperly constructed requests.

In your scenario, you are calling acquireTokenSilent with scopes that span multiple resources (${clientId}/.default, offline_access). Doing this will always result in a cache miss because access token are only scoped to one resource and are cached accordingly. This means you need to make one acquireTokenSilent call for each set of scopes for each resource (e.g. one for ${clientId}/.default and one for offline_access). However, offline_access is not a valid scope in the implicit flow as it is used in other flows to acquire refresh tokens, so your application can pass just the ${clientId}/.default scope to acquireTokenSilent (and acquireTokenRedirect).

We are aware of the problems caused third-party cookies blocking and we are addressing it in MSAL.js v2, which is currently in public preview. See #1000 and msal-browser for details.

I've tried many variations and with separate scopes - the offline_access is following your sample applications which I did to ensure it was completely the same. I've also tried using the v2 releases with @azure/msal-browser but they are broken in the latest beta as shown in your issue tracker with various problems.

There is no public release roadmap or expectation for what you're doing with v2 either. In the Azure control panel for App Registrations it has been showing the warning of how cookies are changing in the browser for at least a few months. How come this project is still relying on browser testing in High Sierra on old versions of Safari and Chrome at least 20 releases back? It might be on Github but this project is not a community run package and led by a development team in-house of Microsoft so please communicate these issues with your support teams about the lack of support for implicit flows for App Registrations. They are so lost they are linking me answers from StackOverflow from 3 years ago.

This issue has not seen activity in 14 days. It may be closed if it remains stale.

This is kinda a major issue, is the only resolution to tell the users to not use incognito tab?

MSAL.js 2.0 is now generally available and will mitigate errors caused by third-party cookie blocking in most scenarios. Please try out the latest version and let us know if you have any feedback.

@jo-arroyo Thanks for letting us know, if companies are still using the implicit flow they won't be able to migrate to MSAL 2.0 right? Because it uses Auth flow with PKCE...if so they have to begin a migration effort i guess...

@jaslloyd Yes, there are steps involved with migrating from 1.x to 2.x. Please see our migration guide here.

This issue has not seen activity in 14 days. It will be closed in 7 days if it remains stale.

This issue has been closed due to inactivity. If this has not been resolved please open a new issue. Thanks!

Was this page helpful?
0 / 5 - 0 ratings