admin管理员组

文章数量:1333417

I have been using the GRAPH API via confidential client with msal/node library. The token generated by the connection flow has the refresh token expiry period of 90 days. I want to be updated with rolling period as silent token exchange is done. But currently we are not able to achieve this. Any suggestion or points we have been missing? Could you also add the details about the lifetime expiry of refresh token and making a new refresh token silently?

export class MsalAuthenticationProvider implements AuthenticationProvider {
  msalClient: ConfidentialClientApplication;
  homeAccountId: string;
  scopeType: MSALScopeType;

  constructor(homeAccountId: string, msalClient: ConfidentialClientApplication, scopeType: MSALScopeType) {
    this.scopeType = scopeType;
    this.msalClient = msalClient;
    this.homeAccountId = homeAccountId;
  }

  /**
   * This method will get called before every request to the msgraph server
   * This should return a Promise that resolves to an accessToken (in case of success) or rejects with error (in case of failure)
   * Basically this method will contain the implementation for getting and refreshing accessTokens
   */
  public async getAccessToken(): Promise<string> {
    const account = await this.msalClient.getTokenCache().getAccountByHomeId(this.homeAccountId);

    let res: AuthenticationResult | null = null;

    if (!account) {
      const message = 'Error: Failed to retrieve account of given homeAccountId from cache.';
      log.debug(message, {
        result: account,
        homeAccountId: this.homeAccountId.substring(1, 8) + '.*****',
        name: 'account not found.'
      });

      throw new GraphClientError(message);
    }

    // Attempt to get the token silently
    // This method uses the token cache and
    // refreshes expired tokens as needed
    log.info('Silently acquiring token for given account from MSALAuthProvider.');

    const scopes = mapMSALTypeToAuthScopes[this.scopeType];
    log.debug('Acquiring token with given scopes:', scopes);

    res = await this.msalClient.acquireTokenSilent({
      scopes,
      account
    });

    if (!res) {
      const message = 'Error: Cannot retrieve accessToken from the MsalAuthenticationProvider object.';
      log.debug(message, {`your text`
        result: res,
        name: 'Access token is null'
      });

      throw new GraphClientError(message);
    }

    return res.accessToken;
  }
}

I have been using the GRAPH API via confidential client with msal/node library. The token generated by the connection flow has the refresh token expiry period of 90 days. I want to be updated with rolling period as silent token exchange is done. But currently we are not able to achieve this. Any suggestion or points we have been missing? Could you also add the details about the lifetime expiry of refresh token and making a new refresh token silently?

export class MsalAuthenticationProvider implements AuthenticationProvider {
  msalClient: ConfidentialClientApplication;
  homeAccountId: string;
  scopeType: MSALScopeType;

  constructor(homeAccountId: string, msalClient: ConfidentialClientApplication, scopeType: MSALScopeType) {
    this.scopeType = scopeType;
    this.msalClient = msalClient;
    this.homeAccountId = homeAccountId;
  }

  /**
   * This method will get called before every request to the msgraph server
   * This should return a Promise that resolves to an accessToken (in case of success) or rejects with error (in case of failure)
   * Basically this method will contain the implementation for getting and refreshing accessTokens
   */
  public async getAccessToken(): Promise<string> {
    const account = await this.msalClient.getTokenCache().getAccountByHomeId(this.homeAccountId);

    let res: AuthenticationResult | null = null;

    if (!account) {
      const message = 'Error: Failed to retrieve account of given homeAccountId from cache.';
      log.debug(message, {
        result: account,
        homeAccountId: this.homeAccountId.substring(1, 8) + '.*****',
        name: 'account not found.'
      });

      throw new GraphClientError(message);
    }

    // Attempt to get the token silently
    // This method uses the token cache and
    // refreshes expired tokens as needed
    log.info('Silently acquiring token for given account from MSALAuthProvider.');

    const scopes = mapMSALTypeToAuthScopes[this.scopeType];
    log.debug('Acquiring token with given scopes:', scopes);

    res = await this.msalClient.acquireTokenSilent({
      scopes,
      account
    });

    if (!res) {
      const message = 'Error: Cannot retrieve accessToken from the MsalAuthenticationProvider object.';
      log.debug(message, {`your text`
        result: res,
        name: 'Access token is null'
      });

      throw new GraphClientError(message);
    }

    return res.accessToken;
  }
}
Share Improve this question asked Nov 20, 2024 at 19:00 Bit GhostBit Ghost 211 silver badge2 bronze badges 1
  • Renew 90 days refresh token again? – Sampath Commented Nov 21, 2024 at 12:12
Add a comment  | 

1 Answer 1

Reset to default 0

The Access Token has a default lifetime of 60 minutes. It can be configured to last up to 24 hours (1,440 minutes) in Azure AD. The Refresh Token has a default maximum lifetime of 90 days. The refresh token window lifetime extends the validity as long as the token is used before expiration.

Refer to Microsoft Q&A for configuring tokens in Azure Active Directory.

Below is the code to renew the refresh token for MSAL silently.

I referred to this documentation to acquire a token to call a web API . Refer to this git for the full code for refresh token.

const express = require("express");
const session = require('express-session');
const cookieParser = require('cookie-parser');
const msal = require('@azure/msal-node');
require('dotenv').config();

const config = require('./config/customConfig.json');
const DiskCache = require('./adalCustomCache');
const msalCachePlugin = require('./msalCachePlugin');

const diskCache = new DiskCache(config.adalCacheLocation);

const REDIRECT_URI = config.redirectUri;

const msalConfig = {
    auth: {
        clientId: config.clientId,
        authority: `${config.authority}/${config.tenantInfo}`,
        clientSecret: process.env.CLIENT_SECRET
    },
    cache: {
        cachePlugin: msalCachePlugin(config.msalCacheLocation)
    },
    system: {
        loggerOptions: {
            loggerCallback(loglevel, message, containsPii) {
                console.log(message);
            },
            piiLoggingEnabled: false,
            logLevel: msal.LogLevel.Verbose,
        }
    }
};
const cca = new msal.ConfidentialClientApplication(msalConfig);

const app = express();

app.use(cookieParser());
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.use(session({
    secret: process.env.CLIENT_SECRET,
    resave: false,
    saveUninitialized: false,
    cookie: {
        secure: false, 
    }
}));

app.get('/', async (req, res, next) => {
    try {
        const account = await cca.getTokenCache().getAccountByHomeId(req.session.account?.homeAccountId);

        if (!account) {
            console.log('Account not found!');
            throw new msal.InteractionRequiredAuthError();
        }

        let tokenResponse;
        try {
            tokenResponse = await cca.acquireTokenSilent({
                account: account,
                scopes: ["user.read"]
            });

            res.json({
                message: 'Successful silent flow token acquisition',
                response: tokenResponse
            });

        } catch (error) {
            if (error instanceof msal.InteractionRequiredAuthError) {
                console.log('Silent token acquisition failed, attempting refresh token flow.');
                diskCache.find({ userId: req.cookies.userId }, async (err, data) => {
                    try {
                        if (err || !data || !data.length) throw new Error('Could not retrieve user cache');

                        const tokenResponse = await cca.acquireTokenByRefreshToken({
                            refreshToken: data[0].refreshToken,
                            scopes: ['https://graph.microsoft/.default'],
                            forceCache: true
                        });
                        req.session.account = tokenResponse.account;

                        res.json({
                            message: 'Successful refresh token flow token acquisition',
                            response: tokenResponse
                        });

                    } catch (error) {
                        console.error(error);
                        next(error);
                    }
                });
            } else {
                next(error);
            }
        }
    } catch (error) {
        next(error);
    }
});

app.post('/redirect', async (req, res, next) => {
    if (req.body.state) {
        if (req.session.state === req.body.state) {
            try {
                const tokenResponse = await cca.acquireTokenByCode({
                    code: req.body.code,
                    scopes: ["user.read"],
                    redirectUri: REDIRECT_URI
                });

                req.session.account = tokenResponse.account;
                res.json({
                    message: 'Successful code flow token acquisition',
                    response: tokenResponse
                });
            } catch (error) {
                next(error);
            }
        } else {
            next(new Error('State does not match'));
        }
    } else {
        next(new Error('State not found'));
    }
});

app.listen(3000, () => console.log(`Listening on port 3000!`));



Output:

本文标签: azureRenew 90 days refresh token for MSAL silentlyStack Overflow