Handling refresh tokens in Azure (Microsoft graph) delegation flow

Nikhil Mandaniya 20 Reputation points
2024-03-19T05:38:05.5466667+00:00

I am working on a project where I need to create events in user's Outlook calendars. The requirement is that job inspection dates should be added to the calendar of relevant users. Additionally, users should have the ability to manually create events on their calendars.

What I have imlemented:

  1. User will be redirected to microsoft login page.
  2. After login Microsoft will give us access token for that user.
  3. Using getTokenCache we are getting refresh token for that user.

Here is the code:

Routes:

router.get('/login', getAuthCodeUrl);
router.get('/callback', handleCallback);

Controllers:

const { ConfidentialClientApplication } = require('@azure/msal-node');
// TEST APP
const clientId = '945bf51b-xxxx-c5a83898b4b8';
const clientSecret = '9mV8Q~xxxx.zf9GqLGt95UUJ_bGdcp';
const msalConfig = {
  auth: {
    clientId: clientId,
    authority: `https://login.microsoftonline.com/common`,
    clientSecret: clientSecret,
  },
};
const redirectUri = 'http://localhost:3000/api/callback';
const scopes = [
  'User.Read',
  'Calendars.ReadWrite',
  'offline_access',
  'openid',
  'profile',
];
const cca = new ConfidentialClientApplication(msalConfig);
const getAuthCodeUrl = async (req, res) => {
  const authCodeUrlParameters = {
    scopes,
    redirectUri,
  };
  const authUrl = await cca.getAuthCodeUrl(authCodeUrlParameters);
  console.log('authUrl: ', authUrl);
  res.redirect(authUrl);
};
const handleCallback = async (req, res) => {
  const tokenRequest = {
    scopes,
    code: req.query.code,
    redirectUri,
    accessType: 'offline',
  };
  try {
    const authResult = await cca.acquireTokenByCode(tokenRequest);
    const accessToken = authResult.accessToken;
    const refreshToken = () => {
      const tokenCache = cca.getTokenCache().serialize();
      const refreshTokenObject = JSON.parse(tokenCache).RefreshToken;
      const refreshToken =
        refreshTokenObject[Object.keys(refreshTokenObject)[0]].secret;
      return refreshToken;
    };
    const tokens = {
      accessToken,
      refreshToken: refreshToken(),
    };
    console.log('tokens: ', tokens);
    // Handle token result, store tokens, etc.
    res.send('Authentication successful. You can close this window.');
  } catch (error) {
    console.error('Error obtaining access token:', error);
    res.status(500).send('Error obtaining access token');
  }
};

Here are my questions:

  1. In our refreshToken function, we are not passing any thing related to this user. I am confused how MSAL gets refresh tokens for this user and not any other?
  2. "access token can only be refreshed for a maximum period of 90 days", I read this on many places while researching. Does user needs to login every 90 days?
  3. Can we get new refresh token without need of user to login again?
  4. How do we know if access token is expired or not? Do we need to call profile (or any other) API for to check expiration of access token?
Microsoft Graph
Microsoft Graph
A Microsoft programmability model that exposes REST APIs and client libraries to access data on Microsoft 365 services.
10,521 questions
Active Directory
Active Directory
A set of directory-based technologies included in Windows Server.
5,822 questions
Microsoft Entra
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. CarlZhao-MSFT 36,736 Reputation points
    2024-03-19T08:38:50.4266667+00:00

    Hi @Nikhil Mandaniya

    In our refreshToken function, we are not passing any thing related to this user. I am confused how MSAL gets refresh tokens for this user and not any other?

    MSAL handles refresh tokens internally. When you acquire an access token using acquireTokenByCode method, MSAL also receives a refresh token tied to the user's session. This refresh token is stored in the token cache and is user-specific. MSAL uses this token to request new access tokens when needed without requiring the user to re-authenticate.

    "access token can only be refreshed for a maximum period of 90 days", I read this on many places while researching. Does user needs to login every 90 days?

    The refresh token received by MSAL can be used to obtain new access tokens for up to 90 days, provided the user remains active. If the user is inactive for a certain period (usually 14 days), the refresh token may become invalid, and the user would need to re-authenticate to obtain a new refresh token.

    Can we get new refresh token without need of user to login again?

    MSAL automatically tries to renew the access token using the refresh token when you call acquireTokenSilent method. If the refresh token is close to expiration, MSAL will also try to get a new refresh token during this process. This is done silently without user interaction, as long as the current refresh token is still valid.

    How do we know if access token is expired or not? Do we need to call profile (or any other) API for to check expiration of access token?

    Access tokens typically have a short lifespan, usually around 1 hour. MSAL provides the acquireTokenSilent method, which checks the expiration of the access token and attempts to renew it using the refresh token if it's expired or about to expire. You don't need to manually check the expiration, MSAL handles this for you.

    Remember that while MSAL abstracts much of the token management process, it's always good practice to handle exceptions where a silent token acquisition might fail, prompting the user to re-authenticate if necessary.

    Hope this helps.

    If the reply is helpful, please click Accept Answer and kindly upvote it. If you have additional questions about this answer, please click Comment.

    1 person found this answer helpful.