Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Empty token Cache #6995

Open
2 tasks
REALSTEVEIG opened this issue Apr 1, 2024 · 1 comment
Open
2 tasks

Empty token Cache #6995

REALSTEVEIG opened this issue Apr 1, 2024 · 1 comment
Labels
bug-unconfirmed A reported bug that needs to be investigated and confirmed confidential-client Issues regarding ConfidentialClientApplications msal-angular Related to @azure/msal-angular package msal-browser Related to msal-browser package Needs: Attention 👋 Awaiting response from the MSAL.js team question Customer is asking for a clarification, use case or information.

Comments

@REALSTEVEIG
Copy link

Core Library

MSAL.js (@azure/msal-browser)

Core Library Version

"@azure/msal-node": "^2.6.6",

Wrapper Library

MSAL Angular (@azure/msal-angular)

Wrapper Library Version

None

Public or Confidential Client?

Confidential

Description

So I am trying to update my tokens whenever they expire (Both access tokens and refresh tokens) However, It seems my token cache is always empty even this method: "acquireTokenByRefreshToken" returns a successfull response with new accessTokens. The token cache is always empty.

Error Message

tokenCache {"Account":{},"IdToken":{},"AccessToken":{},"RefreshToken":{},"AppMetadata":{}}

MSAL Logs

[Mon, 01 Apr 2024 22:21:16 GMT] : [] : @azure/msal-node@2.6.6 : Info - acquireTokenByRefreshToken called
[Mon, 01 Apr 2024 22:21:16 GMT] : [] : @azure/msal-node@2.6.6 : Verbose - initializeRequestScopes called
[Mon, 01 Apr 2024 22:21:16 GMT] : [0dbed1f3-ff5e-44e5-a9b3-2d9aab270d3d] : @azure/msal-node@2.6.6 : Verbose - buildOauthClientConfiguration called
[Mon, 01 Apr 2024 22:21:16 GMT] : [0dbed1f3-ff5e-44e5-a9b3-2d9aab270d3d] : @azure/msal-node@2.6.6 : Verbose - createAuthority called
[Mon, 01 Apr 2024 22:21:16 GMT] : [] : @azure/msal-node@2.6.6 : Verbose - Attempting to get cloud discovery metadata from authority configuration
[Mon, 01 Apr 2024 22:21:16 GMT] : [] : @azure/msal-node@2.6.6 : Verbose - Did not find cloud discovery metadata in the config... Attempting to get cloud discovery metadata from the hardcoded values.
[Mon, 01 Apr 2024 22:21:16 GMT] : [] : @azure/msal-node@2.6.6 : Verbose - Found cloud discovery metadata from hardcoded values.
[Mon, 01 Apr 2024 22:21:16 GMT] : [] : @azure/msal-node@2.6.6 : Verbose - Attempting to get endpoint metadata from authority configuration
[Mon, 01 Apr 2024 22:21:16 GMT] : [] : @azure/msal-node@2.6.6 : Verbose - Did not find endpoint metadata in the config... Attempting to get endpoint metadata from the hardcoded values.
[Mon, 01 Apr 2024 22:21:16 GMT] : [0dbed1f3-ff5e-44e5-a9b3-2d9aab270d3d] : @azure/msal-node@2.6.6 : Info - Building oauth client configuration with the following authority: https://login.microsoftonline.com/common/oauth2/v2.0/token.
[Mon, 01 Apr 2024 22:21:16 GMT] : [0dbed1f3-ff5e-44e5-a9b3-2d9aab270d3d] : @azure/msal-node@2.6.6 : Verbose - Refresh token client created
[Mon, 01 Apr 2024 22:21:17 GMT] : [0dbed1f3-ff5e-44e5-a9b3-2d9aab270d3d] : @azure/msal-common@14.8.1 : Verbose - setCachedAccount called
[Mon, 01 Apr 2024 22:21:17 GMT] : [0dbed1f3-ff5e-44e5-a9b3-2d9aab270d3d] : @azure/msal-common@14.8.1 : Warning - Account used to refresh tokens not in persistence, refreshed tokens will not be stored in the cache

Network Trace (Preferrably Fiddler)

  • Sent
  • Pending

MSAL Configuration

const msalConfig = {
  auth: {
    clientId: OAUTH.MICROSOFT_ENV.MICROSOFT_CLIENT_ID_V2 ?? '',
    authority: OAUTH.MICROSOFT_ENV.MICROSOFT_AUTHORITY_V2,
    clientSecret: OAUTH.MICROSOFT_ENV.MICROSOFT_CLIENT_SECRET_V2,
  },
  system: {
    loggerOptions: {
      loggerCallback(_loglevel: any, message: any, _containsPii: any) {
        console.log(message);
      },
      piiLoggingEnabled: false,
      logLevel: LogLevel.Verbose,
    },
  },
};

Relevant Code Snippets

// Function to refresh access token using refresh token
const refreshAccessToken = async (
  refreshToken: string,
  req: Request,
): Promise<Record<string, unknown>> => {
  app.locals.msalClient = new msal.ConfidentialClientApplication(msalConfig);
  const refreshTokenRequest = {
    scopes: [
      'user.read',
      'calendars.readwrite',
      'mailboxsettings.read',
      'offline_access',
    ],
    accessType: 'offline',
    refreshToken,
  };

  try {
    const response = await req.app.locals.msalClient.acquireTokenByRefreshToken(
      refreshTokenRequest,
    );

    console.log('response', response);

    const refreshToken2 = async (): Promise<any> => {
      const tokenCache = await req.app.locals.msalClient
        .getTokenCache()
        .serialize();

      console.log('tokenCache', tokenCache);

      const refreshTokenObject = JSON.parse(tokenCache).RefreshToken;

      const myRefreshToken =
        refreshTokenObject[Object.keys(refreshTokenObject)[0]].secret;

      return myRefreshToken;
    };

    const updatedCredentials = {
      newAccesssToken: response?.accessToken,
      newRefreshToken: await refreshToken2(),
      newExpiresOn: response?.expiresOn,
    };

    return updatedCredentials;
  } catch (error) {
    // Handle token refresh failure
    throw new Error(error as string | undefined);
  }
};


//Get all calendar service
const getAllCalendarServices = async (
  req: Request,
  user: string,
): Promise<any> => {
  const account = await AccessTokenModel.findOne({
    user,
    provider: 'microsoft',
  })
    .sort({ createdAt: -1 })
    .limit(1);

  if (!account) {
    return {
      errorCode: 'missing-access-token',
      statusCode: 403,
      message: 'Kindly authorize the microsoft App to continue',
    };
  }

  if (account.expiryTime.getTime() < Date.now()) {
    const newTokens = await refreshAccessToken(account.refreshToken, req);

    await AccessTokenModel.findOneAndUpdate(
      { user, provider: 'microsoft' },
      {
        accessToken: newTokens.newAccessToken,
        expiryTime: newTokens.newExpiresOn,
      },
      { new: true, runValidators: true, sort: { createdAt: -1 } },
    );

    const newAccount = await AccessTokenModel.findOne({
      user,
      provider: 'microsoft',
    })
      .sort({ createdAt: -1 })
      .limit(1);

    // Use the new access token to make the request
    const calendarsResponse = await axios.get(
      'https://graph.microsoft.com/v1.0/me/calendars',
      {
        headers: {
          // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
          Authorization: `Bearer ${newAccount?.accessToken}`,
        },
      },
    );
    return calendarsResponse.data;
  }

  const calendarsResponse = await axios.get(
    'https://graph.microsoft.com/v1.0/me/calendars',
    {
      headers: {
        Authorization: `Bearer ${account.accessToken}`,
      },
    },
  );

  return calendarsResponse.data;
};

//Get all calendars controllers
const getAllCalendarsController = async (
  req: Request,
  res: Response,
): Promise<any> => {
  try {
    const user = req.session.user?.email;
    const allCalendars = await getAllCalendarServices(req, user!);
    return res.status(200).json(allCalendars);
  } catch (error: any) {
    // eslint-disable-next-line no-console
    // console.log('error', error);
    if (error.response.status !== 200) {
      return res.status(error.response.status).json(error.response.data.error);
    }
    return res.status(500).json(error.response.data);
  }
};

Reproduction Steps

  1. Set up DB for storing access tokens and refresh tokens. (AccessTokenModel).
  2. Import the getAllCalendar service function into your conroller file.
  3. Make a call to the getAllCalendarController endpoint.
  4. If accesTokenModel.expiry time === true/ access token has expired, endpoint will call the refreshAccessToken to obtain a new accesstoken and refreshtoken.

Here is a link to the sample code on github: SAMPLE OF CODE ON GITHUB

How to run the code.

  1. Git clone: Sample code
  2. npm install
  3. npm run dev
  4. Auth endpoint: http://localhost:8000/install
  5. callback endpoint : http://localhost:8000/callback
  6. Get all calendars endpoin: http://localhost:8000/calendars

Expected Behavior

I expect that the refreshAccessToken function should not only generate new accessTokens but should also store this access token in the cache along with the refresh token in the token cache.

Identity Provider

Entra ID (formerly Azure AD) / MSA

Browsers Affected (Select all that apply)

Chrome

Regression

No response

Source

External (Customer)

@REALSTEVEIG REALSTEVEIG added bug-unconfirmed A reported bug that needs to be investigated and confirmed question Customer is asking for a clarification, use case or information. labels Apr 1, 2024
@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs: Attention 👋 Awaiting response from the MSAL.js team label Apr 1, 2024
@github-actions github-actions bot added confidential-client Issues regarding ConfidentialClientApplications msal-angular Related to @azure/msal-angular package msal-browser Related to msal-browser package labels Apr 1, 2024
@BertVanHeckeCertifisc
Copy link

+1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug-unconfirmed A reported bug that needs to be investigated and confirmed confidential-client Issues regarding ConfidentialClientApplications msal-angular Related to @azure/msal-angular package msal-browser Related to msal-browser package Needs: Attention 👋 Awaiting response from the MSAL.js team question Customer is asking for a clarification, use case or information.
Projects
None yet
Development

No branches or pull requests

2 participants