Issue with Refresh Token Acquisition in MSAL Node.js Application

jhirono 20 Reputation points
2025-03-24T19:36:47.38+00:00

Github Repo: https://github.com/jhirono/todoMCP

Node.js file for auth: https://github.com/jhirono/todoMCP/blob/main/src/auth-server.js

Issue Description

Our application is unable to obtain a refresh token when authenticating with Microsoft Graph API using MSAL Node.js. Despite explicitly requesting the offline_access scope and forcing consent, the refresh token is not included in the token response.

Environment

  • MSAL Node.js
  • Authentication flow: Authorization Code Flow
  • Application type: Confidential Client (Web application)
// MSAL Configuration
const msalConfig = {
  auth: {
    clientId: process.env.CLIENT_ID,
    authority: `https://login.microsoftonline.com/${process.env.TENANT_ID}`,
    clientSecret: process.env.CLIENT_SECRET
  }
};

// Requested Scopes
const scopes = [
  'offline_access',
  'openid',
  'profile',
  'Tasks.Read',
  'Tasks.Read.Shared',
  'Tasks.ReadWrite',
  'Tasks.ReadWrite.Shared',
  'User.Read'
];

Steps Tried

  1. Azure Portal Configuration
  • Verified "Allow public client flows" is disabled
  • Confirmed offline_access permission is explicitly added and admin consent granted
  • Double-checked all required API permissions
  1. Authentication Parameters
  • Added prompt: 'consent' to force consent screen
  • Placed offline_access first in scopes array
  • Added openid and profile scopes
  1. Different Authority URLs
  1. Debugging Steps
  • Implemented detailed MSAL logging
  • Added cache plugin to track token caching behavior
  • Verified all scopes in token response
  • Cleared browser cookies and revoked app permissions between attempts

Current Behavior

  • Successfully receives access token
  • Successfully authenticates with Microsoft Graph API
  • Receives all requested scopes EXCEPT offline_access
  • No refresh token in the response

Expected Behavior

  • Receive refresh token along with access token
  • Have offline_access included in granted scopes

Questions for Support

  1. Why is the offline_access scope being dropped from the granted scopes?
  2. Are there any additional configuration requirements for obtaining refresh tokens?
  3. Are there any known issues with refresh token acquisition in this scenario?

Logs

We can provide detailed MSAL logs and token response structure (with sensitive data removed) if needed.

Microsoft Security | Microsoft Entra | Microsoft Entra ID
0 comments No comments
{count} votes

Accepted answer
  1. Goutam Pratti 6,170 Reputation points Microsoft External Staff Moderator
    2025-03-26T08:23:54.07+00:00

    Hello @jhirono ,

    I Understand your application is unable to obtain a refresh token when authenticating with Microsoft Graph API using MSAL Node.js. The refresh token is not included in the token response.As your application is unable to obtain a refresh token when authenticating with Microsoft Graph API using MSAL Node.js. Despite explicitly requesting the offline_access scope and forcing consent, the refresh token is not included in the token response.

    MSAL Node, like other MSAL libraries, does not expose refresh tokens for security reasons. Instead, MSAL handles the token refresh process automatically.

    If you need to retrieve the refresh token, it is not directly included in the response. Instead, it is stored in the MSAL token cache, which keeps track of tokens for future use. MSAL manages this cache internally, and you can access it when needed using the getTokenCache() method.

    To retrieve the refresh tokens and call the User Info Endpoint, refer to the modifications outlined in the document here: StackOverflow link.

    As for implementing persistent authentication for your desktop application, I recommend using a conditional access policy with a sign-in frequency that requires periodic authentication. This approach will ensure users can maintain continuous access to the application..

    Follow the document for detailed explanation and Implementation of conditional Access policy and Sign in frequency.

    For Additional Information: MSAL Refresh Token, Refresh Token Grant

    Hope this Helps Let me know if you any additional Queries Happy to assist you further.

    Please "Accept the answer" if the information helped you. This will help us and others in the community as well.

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Bruce (SqlWork.com) 77,851 Reputation points Volunteer Moderator
    2025-03-24T19:54:37.3266667+00:00

    Because you are using a client secret, you don’t get a refresh token. What do you need it for? Your code has the secret and can get a new access token without using a refresh token. Refresh tokens are for when the app can not be trusted with having login credentials and must use the clients.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.