即使在 'offline_access' 范围内,onedrive 也不会 return 刷新令牌

onedrive does not return refresh token even with 'offline_access' scope

我正在尝试获取用户的令牌,以便将一个驱动器集成到我正在构建的应用程序中

我首先获得授权URL,这是端点实现

const pca = new msal.ConfidentialClientApplication(config);
exports.getAuthUrl = (req, res) => {
  const authCodeUrlParameters = {
    scopes: ['user.read', 'files.readwrite', 'offline_access'],

    redirectUri: 'https://localhost:8080/onedrive',
  };
  // get url to sign user in and consent to scopes needed for application
  pca
    .getAuthCodeUrl(authCodeUrlParameters)
    .then((response) => {
      res.status(200).send(response);
    })
    .catch((error) => console.log(JSON.stringify(error)));
};

然后使用我在客户端认证成功后返回的代码作为参数传递到第二个端点来获取令牌

exports.getToken = (req, res) => {
  const tokenRequest = {
    code: req.query.code,
    scopes: ['user.read', 'files.readwrite', 'offline_access'],

    redirectUri: 'https://localhost:8080/onedrive',
  };

  pca
    .acquireTokenByCode(tokenRequest)
    .then((response) => {
      console.log('\nResponse: \n:', response);
      res.status(200).send(response);
    })
    .catch((error) => {
      console.log(error);
      res.status(500).send(error);
    });
};

因此,如官方文档中所述,如果您添加 offline_access 作用域,您会得到一个刷新令牌

有人对此有经验吗?我用的这两个库部分代码微软已经提供了const msal = require('@azure/msal-node');

好吧,经过几天的研究,我发现 msal-node 在设计上没有向最终用户公开刷新令牌。当您需要新的访问令牌时,它会在内部存储和使用。每次需要访问令牌时都应调用 acquireTokenSilent,msal-node 将通过向您返回缓存令牌或使用刷新令牌获取新访问令牌来管理令牌。 所以我所做的实际上是直接调用 Microsoft 提供的端点 您应该首先使用本文档 [https://docs.microsoft.com/en-us/onedrive/developer/rest-api/getting-started/msa-oauth?view=odsp-graph-online][1] 中提供的 URL 获取代码 获取代码并将其传递到下一个点,即以下

exports.getToken = async (req, res) => {
  request.post(
    'https://login.live.com/oauth20_token.srf',
    {
      form: {
        code: req.body.code,
        client_id: 'CLIENT-ID',
        redirect_uri: 'REDIRECT-URI',
        client_secret: 'CLIENT-SECRET',
        grant_type: 'authorization_code',
      },
    },
    async function (err, httpResponse, body) {
      if (err) {
        res.status(500).send({ Message: err.message });
      } else {
        let response = JSON.parse(body);
       res.status(200).send({ Body: JSON.parse(body) });
      }
    }
  );
};

这就是我让它工作的方式,使用 msal 没有办法

这是获取刷新和访问令牌的方法..

/*
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License.
 */
const express = require("express");
const msal = require('@azure/msal-node');

const SERVER_PORT = process.env.PORT || 3000;
const REDIRECT_URI = "http://localhost:3000/redirect";

// Before running the sample, you will need to replace the values in the config, 
// including the clientSecret
const config = {
    auth: {
        clientId: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        authority: "https://login.microsoftonline.com/84fb56d3-e15d-4ae1-acd7-cbf83c4c0af3",
        clientSecret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    },
    system: {
        loggerOptions: {
            loggerCallback(loglevel, message, containsPii) {
                console.log(message);
            },
            piiLoggingEnabled: false,
            logLevel: msal.LogLevel.Verbose,
        }
    }
};

// Create msal application object
const pca = new msal.ConfidentialClientApplication(config);

// Create Express App and Routes
const app = express();

app.get('/', (req, res) => {
    const authCodeUrlParameters = {
        scopes: ["user.read","offline_access"],
        redirectUri: REDIRECT_URI,
        prompt:'consent'
    };
    // get url to sign user in and consent to scopes needed for application
    pca.getAuthCodeUrl(authCodeUrlParameters).then((response) => {
        res.redirect(response);
    }).catch((error) => console.log(JSON.stringify(error)));
});

app.get('/redirect', (req, res) => {
    const tokenRequest = {
        code: req.query.code,
        scopes: ["user.read","offline_access"],
        redirectUri: REDIRECT_URI,
        accessType: 'offline',
    };
    pca.acquireTokenByCode(tokenRequest).then((response) => {
        const accessToken = response.accessToken;
        const refreshToken = () => {
            const tokenCache = pca.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)
        res.sendStatus(200);
    }).catch((error) => {
        console.log(error);
        res.status(500).send(error);
    });
});


app.listen(SERVER_PORT, () => console.log(`Msal Node Auth Code Sample app listening on port ${SERVER_PORT}!`))