【问题标题】:CompactToken parsing failed with error code: 80049217 when using passport library to access Microsoft Graph APICompactToken 解析失败,错误代码:80049217 使用护照库访问 Microsoft Graph API 时
【发布时间】:2020-02-28 23:25:57
【问题描述】:

我正在使用 'passport-azure-ad-oauth2' npm 模块来获取访问令牌,然后我可以将其传递给 MS Graph API。

passport.use(new AzureAdOAuth2Strategy({
    clientID: process.env.OUTLOOK_CLIENT_ID,
    clientSecret: process.env.OUTLOOK_SECRET,
    callbackURL: '/auth/outlook/callback',
},
    function (accesstoken: any, refresh_token: any, params: any, profile, done) {
        logger.info('Completed azure sign in for : ' + JSON.stringify(profile));
        logger.info('Parameters returned: ' + JSON.stringify(params));
        const decodedIdToken: any = jwt.decode(params.id_token);
        logger.info('Outlook Access Token:' + accesstoken);
        logger.info('Decoded Token: ' + JSON.stringify(decodedIdToken, null, 2));

        process.env['OUTLOOK_ACCESS_TOKEN'] = accesstoken;
        // add new user with token or update user's token here, in the database

    }));

然后,使用 '@microsoft/microsoft-graph-client' npm 模块,从 Graph API 获取日历事件,如下所示:

try {
    const client = this.getAuthenticatedClient(process.env['OUTLOOK_ACCESS_TOKEN']);
    const resultSet = await client
                .api('users/' + userId + '/calendar/events')
                .select('subject,organizer,start,end')
                .get();
    logger.info(JSON.stringify(resultSet, null, 2));
} catch (err) {
    logger.error(err);
}

getAuthenticatedClient(accessToken) {
    logger.info('Using accestoken for initialising Graph Client: ' + accessToken);
    const client = Client.init({
        // Use the provided access token to authenticate requests
        authProvider: (done) => {
            done(null, accessToken);
        }
    });

    return client;
}

但是,但是,使用成功登录时提供的 accessToken,我收到以下错误: CompactToken 解析失败,错误代码:80049217

任何建议我做错了什么???

更新: 这些是我使用的范围:'openid,profile,offline_access,calendars.read'

更新: 稍微编辑范围后,现在我收到以下错误:无效的受众。

解码在 jwt.ms 收到的令牌时,这是“aud”的值:“00000002-0000-0000-c000-000000000000”

passport-azure-ad-oauth2 是否是用于检索 MS Graph API 令牌的错误库?

【问题讨论】:

  • 根据我的错误信息,能否请您抓住process.env['OUTLOOK_ACCESS_TOKEN'] = accesstoken; 打印您的访问令牌?
  • 原来,passport-azure-ad-oauth2 为旧的 Azure AD Graph API 提供了访问令牌。所以我切换到 passport-microsoft,它为新的 Microsoft Graph API 检索令牌

标签: node.js microsoft-graph-api auth0 adal microsoft-graph-calendar


【解决方案1】:

根据我的测试,我们可以使用下面的代码来获取访问令牌。 app.js

require('dotenv').config();
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var session = require('express-session');
var flash = require('connect-flash');
var passport = require('passport');
var OIDCStrategy = require('passport-azure-ad').OIDCStrategy;


// Configure simple-oauth2
const oauth2 = require('simple-oauth2').create({
  client: {
    id: process.env.OAUTH_APP_ID,
    secret: process.env.OAUTH_APP_PASSWORD
  },
  auth: {
    tokenHost: process.env.OAUTH_AUTHORITY,
    authorizePath: process.env.OAUTH_AUTHORIZE_ENDPOINT,
    tokenPath: process.env.OAUTH_TOKEN_ENDPOINT
  }
});
var users = {};

// Passport calls serializeUser and deserializeUser to
// manage users
passport.serializeUser(function(user, done) {
  // Use the OID property of the user as a key
  users[user.profile.oid] = user;
  done (null, user.profile.oid);
});

passport.deserializeUser(function(id, done) {
  done(null, users[id]);
});

// Callback function called once the sign-in is complete
// and an access token has been obtained
async function signInComplete(iss, sub, profile, accessToken, refreshToken, params, done) {
  if (!profile.oid) {
    return done(new Error("No OID found in user profile."), null);
  }


  // Create a simple-oauth2 token from raw tokens
  let oauthToken = oauth2.accessToken.create(params);

  // Save the profile and tokens in user storage
  users[profile.oid] = { profile, oauthToken };
  return done(null, users[profile.oid]);
}

// Configure OIDC strategy
passport.use(new OIDCStrategy(
  {
    identityMetadata: `${process.env.OAUTH_AUTHORITY}${process.env.OAUTH_ID_METADATA}`,
    clientID: process.env.OAUTH_APP_ID,
    responseType: 'code id_token',
    responseMode: 'form_post',
    redirectUrl: process.env.OAUTH_REDIRECT_URI,
    allowHttpForRedirectUrl: true,
    clientSecret: process.env.OAUTH_APP_PASSWORD,
    validateIssuer: false,
    passReqToCallback: false,
    scope: process.env.OAUTH_SCOPES.split(' ')
  },
  signInComplete
));

更多详情请参考documentsample

【讨论】:

  • 我试过这个,但是 OIDCStrategy 需要会话。我们已经在使用 jwt。有没有办法在没有会话的情况下使用这个策略??
  • 什么意思?你想使用 AzureAdOAuth2Strategy 吗?
  • 在我正在开发的产品中。我们使用 google oauth2 使用护照模块登录并获取访问令牌,该令牌用于获取用户的日历事件。现在我正在尝试将 Office 365 集成到其中。但是,我们使用 jwt 来存储身份验证数据,所以不要认为 OIDCStrategy 适合这里,因为它使用会话。我需要一个可以与 jwt 一起使用的策略
【解决方案2】:

原来有一个用于 microsoft-graph api 的护照库:passport-microsoft

我使用了该软件包中的 MicrosoftStrategy,一切似乎都运行良好。

passport-azure-ad-oauth2 用于旧的 Azure AD Graph API,而 passport-microsoft 用于新的 Microsoft Graph API

【讨论】:

  • 如果您的问题已经解决,请采纳。它可能会帮助更多的人。
【解决方案3】:

我有同样的问题。就我而言,授权标头格式错误:

Bearereyxxxx

而不是

承载 eyxxxx

我是那个项目的新手,但它似乎事先被 Azure 接受。

【讨论】:

    【解决方案4】:

    我解决了这个问题,只通过 authenticationProvider 中的 accessToken 而不是旧的“Bearer”+令牌:例如:

    TokenCredential tokenCredential = tokenRequestContext -> Mono.just(new AccessToken(accessToken, OffsetDateTime.MAX));
    IAuthenticationProvider authenticationProvider = new TokenCredentialAuthProvider(tokenCredential);
    

    【讨论】:

      【解决方案5】:

      我在使用 Graph API 时遇到此错误,因为我在对结果进行分页时添加了多个授权标头。每个@odata.nextlink 页面都添加了相同的令牌,导致它在初始请求后中断并显示此错误消息。

      这是我的 C# 代码:

      private Tuple<JToken, JToken> GetUsersAndNextLink()
          {
              client.BaseUrl = new Uri("https://graph.microsoft.com/v1.0/users");
              var request = new RestRequest("", Method.GET);
              client.AddDefaultHeader("Authorization", string.Format("Bearer {0}", Token));
              IRestResponse response = client.Execute(request);
              var content = response.Content;
              var des = JsonConvert.DeserializeObject<JObject>(content);
              var nextlink = des["@odata.nextLink"];
      
              var value = des["value"];
              return new Tuple<JToken, JToken>(value, nextlink);
          }
      
          private Tuple<JToken, JToken> GetUsersAndNextLink(string prevnextlink)
          {
              client.BaseUrl = new Uri(prevnextlink);
              var request = new RestRequest("", Method.GET);
              client.AddDefaultHeader("Authorization", string.Format("Bearer {0}", Token));
              IRestResponse response = client.Execute(request);
              var content = response.Content;
              var des = JsonConvert.DeserializeObject<JObject>(content);
              var nextlink = des["@odata.nextLink"];
              var value = des["value"];
              return new Tuple<JToken, JToken>(value, nextlink);
          }
      

      每次@odata.nextlink 值出现在对结果的分页响应中时,代码都会进行迭代。但是,添加多个标头每次都会导致错误。

      删除 GetUsersAndNextLink(string prevnextlink) 方法调用的第三行为我解决了这个问题。

      确保您的授权标头井井有条 - 在使用 Graph API 时,这似乎是针对这些问题的所有错误代码。

      【讨论】:

        【解决方案6】:

        接受的答案仅对使用特定 passport-azure-ad-oauth2 npm 模块的人有所帮助,这是 OP 的情况,但标题对于在使用 Microsoft Graph 时遇到此错误的任何情况都是通用的。如果您尝试通过(错误地)在授权标头中传递刷新令牌而不是有效的访问令牌来连接到 Graph,您将收到此错误:

        获取https://graph.microsoft.com/v1.0/me 授权:Bearer wronglySuppliedRefreshTokenHere

        有些人可能已经尝试过这样做,因为他们的访问令牌已过期,希望刷新令牌能够工作。

        要使用刷新令牌获取有效的身份验证令牌,您需要发出 http POST 请求

        https://login.microsoftonline.com/{yourTenantId}/oauth2/v2.0/tokenrequest

        带有 (1) 授权标头,如下所示:

        授权:承载 {yourExpiredAccessToken}

        和 (2) Content-Type 标头如下:

        内容类型:application/x-www-form-urlencoded

        和 (3) 正文包含键值对(其中值是 urlencoded),看起来像这样(不包括花括号,并用实际值替换花括号内的变量)...

        client_id={yourClientId}&grant_type=refresh_token&scope=offline_access%20https%3A%2F%2Fgraph.microsoft.com%2FUser.Read&client_secret={yourClientSecret}&refresh_token={yourRefreshToken}

        注意范围的值只是一个例子;您应该使用最初请求访问令牌和刷新令牌时使用的相同范围。

        提交请求,您将收到一个包含有效访问令牌的 json 响应,然后您可以在 Authentication Bearer 标头中使用该令牌,您将能够成功连接。

        还请注意,当访问令牌过期时,您在任何时候发出请求时都需要捕获 ServiceException ("code":"InvalidAuthenticationToken", "message":"Access token has expired or is not yet valid.") .通过使用 grant_type=refresh_token 重新提交 POST 来处理它,并再次使用新的身份验证令牌更新您的标头并重试。

        【讨论】:

          猜你喜欢
          • 2022-10-25
          • 2017-10-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-05-23
          • 1970-01-01
          • 1970-01-01
          • 2019-08-11
          相关资源
          最近更新 更多