使用护照库访问 Microsoft Graph 时,CompactToken 解析失败,错误代码:80049217 API
CompactToken parsing failed with error code: 80049217 when using passport library to access Microsoft Graph API
我正在使用 '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 的令牌?
根据我的测试,我们可以使用下面的代码来获取access token。
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
));
原来有一个用于 microsoft-graph api 的护照库:passport-microsoft
我使用了那个包中的 MicrosoftStrategy,一切似乎都运行良好。
passport-azure-ad-oauth2 用于旧的 Azure AD Graph API,而 passport-microsoft 是对于新的 Microsoft Graph API
我遇到了同样的问题。就我而言,授权 header 格式错误:
Bearereyxxxx
而不是
承载 eyxxxx
我是那个项目的新手,但它似乎以前被 Azure 接受过。
我解决了这个问题,只传递 authenticationProvider 中的 accessToken 而不是旧的“Bearer”+ token:例如:
TokenCredential tokenCredential = tokenRequestContext -> Mono.just(new AccessToken(accessToken, OffsetDateTime.MAX));
IAuthenticationProvider authenticationProvider = new TokenCredentialAuthProvider(tokenCredential);
我在图表 API 中遇到了这个错误,因为我在翻阅结果时添加了多重授权 headers。每个 @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 值出现在对结果进行分页的响应中时,代码就会进行迭代。但是,添加多个 headers 每次都会导致错误。
删除 GetUsersAndNextLink(string prevnextlink) 方法调用的第三行为我解决了这个问题。
确保您的授权 headers 是正确的 - 这似乎是使用 Graph API.
时针对这些问题的所有错误代码
接受的答案仅帮助使用特定 passport-azure-ad-oauth2 npm 模块的人,这是 OP 的情况,但标题对于使用 Microsoft Graph 时出现此错误的任何情况都是通用的。如果您尝试通过(错误地)在授权 header 中传递刷新令牌而不是有效的访问令牌来连接到 Graph,您将收到此错误:
获得https://graph.microsoft.com/v1.0/me
授权:Bearer 错误地提供 RefreshTokenHere
有些人可能已经尝试过此操作,因为他们的访问令牌已过期,希望刷新令牌能够正常工作。
要使用刷新令牌获取有效的身份验证令牌,您需要向
发出 http POST 请求
https://login.microsoftonline.com/{yourTenantId}/oauth2/v2.0/tokenrequest
with (1) Authorization Header, 像这样:
授权:不记名 {yourExpiredAccessToken}
和 (2) Content-Type header 像这样:
Content-Type: application/x-www-form-urlencoded
和 (3) body 包含 key-value 对(其中值经过 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 响应,其中包含一个有效的访问令牌,然后您可以在身份验证承载中使用该令牌 header,您将能够成功连接。
另请注意,您每次发出请求时都需要捕获 ServiceException ("code":"InvalidAuthenticationToken", "message":"Access token has expired or is not yet valid.")已过期。通过使用 grant_type=refresh_token 重新提交 POST 来处理它,然后使用新的身份验证令牌再次更新您的 header 并重试。
我正在使用 '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 的令牌?
根据我的测试,我们可以使用下面的代码来获取access token。 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
));
原来有一个用于 microsoft-graph api 的护照库:passport-microsoft
我使用了那个包中的 MicrosoftStrategy,一切似乎都运行良好。
passport-azure-ad-oauth2 用于旧的 Azure AD Graph API,而 passport-microsoft 是对于新的 Microsoft Graph API
我遇到了同样的问题。就我而言,授权 header 格式错误:
Bearereyxxxx
而不是
承载 eyxxxx
我是那个项目的新手,但它似乎以前被 Azure 接受过。
我解决了这个问题,只传递 authenticationProvider 中的 accessToken 而不是旧的“Bearer”+ token:例如:
TokenCredential tokenCredential = tokenRequestContext -> Mono.just(new AccessToken(accessToken, OffsetDateTime.MAX));
IAuthenticationProvider authenticationProvider = new TokenCredentialAuthProvider(tokenCredential);
我在图表 API 中遇到了这个错误,因为我在翻阅结果时添加了多重授权 headers。每个 @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 值出现在对结果进行分页的响应中时,代码就会进行迭代。但是,添加多个 headers 每次都会导致错误。
删除 GetUsersAndNextLink(string prevnextlink) 方法调用的第三行为我解决了这个问题。
确保您的授权 headers 是正确的 - 这似乎是使用 Graph API.
时针对这些问题的所有错误代码接受的答案仅帮助使用特定 passport-azure-ad-oauth2 npm 模块的人,这是 OP 的情况,但标题对于使用 Microsoft Graph 时出现此错误的任何情况都是通用的。如果您尝试通过(错误地)在授权 header 中传递刷新令牌而不是有效的访问令牌来连接到 Graph,您将收到此错误:
获得https://graph.microsoft.com/v1.0/me 授权:Bearer 错误地提供 RefreshTokenHere
有些人可能已经尝试过此操作,因为他们的访问令牌已过期,希望刷新令牌能够正常工作。
要使用刷新令牌获取有效的身份验证令牌,您需要向
发出 http POST 请求https://login.microsoftonline.com/{yourTenantId}/oauth2/v2.0/tokenrequest
with (1) Authorization Header, 像这样:
授权:不记名 {yourExpiredAccessToken}
和 (2) Content-Type header 像这样:
Content-Type: application/x-www-form-urlencoded
和 (3) body 包含 key-value 对(其中值经过 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 响应,其中包含一个有效的访问令牌,然后您可以在身份验证承载中使用该令牌 header,您将能够成功连接。
另请注意,您每次发出请求时都需要捕获 ServiceException ("code":"InvalidAuthenticationToken", "message":"Access token has expired or is not yet valid.")已过期。通过使用 grant_type=refresh_token 重新提交 POST 来处理它,然后使用新的身份验证令牌再次更新您的 header 并重试。