微软图 return "access token is empty"
Microsoft graph return "access token is empty"
我post这个请求:
POST https://login.microsoftonline.com:443/{my-tennant-here}/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id={client id here}
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&client_secret={client secret here}
&grant_type=client_credentials
这个returns:
{
"token_type": "Bearer",
"expires_in": 3599,
"ext_expires_in": 0,
"access_token": "eyJ0eX......
}
我已经使用 jwt.io 解码了令牌,它绝对不是空的。它包含 14 个声明。 aud、iss、tid 等...
然后我在此请求中使用访问令牌
GET https://graph.microsoft.com/v1.0/users
Athorization: Bearer eyJ0eX...
然后我得到一个 401 Unauthorized with this body:
{
"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token is empty.",
"innerError": {
"request-id": "",
"date": "2018-08-14T15:41:44"
}
}
}
预期结果是 200 Ok,正文包含用户列表
这是否仅仅意味着我的应用未经授权,错误消息只是误导(访问令牌为空)?
还是我做错了什么?
更新:
我注意到虽然令牌确实包含声明,但它没有范围声明,这对我来说似乎有点奇怪。我会假设它有 User.Read.All 范围。应用程序(客户端 id/client 秘密)应具有此权限。
我收到的令牌中的声明具有以下声明:
aud: "<a href="https://graph.microsoft.com" rel="nofollow noreferrer">https://graph.microsoft.com</a>",
iss: "<a href="https://sts.windows.net/my" rel="nofollow noreferrer">https://sts.windows.net/my</a> tennant id",
iat: timestamp
nbf: timestamp
exp: timestamp
aio: looks like some kind of signature
app_displayname: "the expected app name"
appid: "the expected appid"
appidacr: "1"
idp: "<a href="https://sts.windows.net/" rel="nofollow noreferrer">https://sts.windows.net/</a>...."
oid: "GUID"
sub: "GUID"
tid: "my tennant id"
uti: "value"
ver: 1.0
</pre>
授权 header 拼写错误。
所以 "Access token is empty" 可能实际上意味着不存在甚至 "No authorization header in request"。
对于 User.Read.All 范围,您无法获得用户同意。必须征得管理员同意。看起来您可能没有使用管理员帐户同意您的应用程序。
要做到这一点:
GET https://login.microsoftonline.com/{tenant}/adminconsent
?client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&state=12345
&redirect_uri=http://localhost/myapp/permissions
然后获取访问令牌,您应该获取管理员已同意用户使用的范围。
一个 URL 有效,另一个无效。
这个有效:
endpoint = "https://graph.microsoft.com/v1.0/reports/getOffice365ActiveUserDetail%28period%3D%27D7%27%29"
headers = {"Authorization": 'Bearer ' + access_token_gmc}
response = requests.get(endpoint, headers=headers)
但是这个没有:
endpoint = "https://graph.microsoft.com/v1.0//users/myuserid/calendars"
headers = {"Authorization": 'Bearer ' + access_token_gmc}
response = requests.get(endpoint, headers=headers)
请确保拼写正确。
对我来说,我的问题是我在请求 url 和授权 header 之间设置了换行符,改为 body。
错误:
GET https://graph.microsoft.com/v1.0/users
Authorization: Bearer {{token}}
正确:
GET https://graph.microsoft.com/v1.0/users
Authorization: Bearer {{token}}
一个愚蠢的错误,但很容易被忽视 - 如果你遇到这个 post 你可能犯了一个愚蠢的错误,比如 OP(打字错误)或这个。再次查看您的请求语法!
我在使用 MSAL
.
的 angular
应用程序中遇到了同样的错误
而这一切都是因为MSALAngularConfigFactory
中提供的错误API scope
。我之前有 environment
。
export const environment = {
production: false,
clientId: 'clientid',
redirectUrl: 'http://localhost:4200',
graphApiUrl: 'https://graph.microsoft.com/v1.0',
graphGetUserImage: '/me/photo/$value',
protectedResourceMap: [
['http://localhost:65498/api', ['api.access']],
['https://graph.microsoft.com/beta', ['user.read']]
] as [string, string[]][],
authority: 'https://login.microsoftonline.com/organizations'
};
如您所见,我在 protectedResourceMap
中给出了 https://graph.microsoft.com/beta
,这是错误的。相反,我们应该给出 https://graph.microsoft.com/v1.0/
。所以这是正确的 environment
.
export const environment = {
production: false,
clientId: 'clientid',
redirectUrl: 'http://localhost:4200',
graphApiUrl: 'https://graph.microsoft.com/v1.0',
graphGetUserImage: '/me/photo/$value',
protectedResourceMap: [
['http://localhost:65498/api', ['api.access']],
['https://graph.microsoft.com/v1.0/', ['user.read']]
] as [string, string[]][],
authority: 'https://login.microsoftonline.com/organizations'
};
我在 app.module.ts
中使用它,如下所示。
function MSALAngularConfigFactory(): MsalAngularConfiguration {
return {
popUp: false,
protectedResourceMap: environment.protectedResourceMap,
};
}
我post这个请求:
POST https://login.microsoftonline.com:443/{my-tennant-here}/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id={client id here}
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&client_secret={client secret here}
&grant_type=client_credentials
这个returns:
{
"token_type": "Bearer",
"expires_in": 3599,
"ext_expires_in": 0,
"access_token": "eyJ0eX......
}
我已经使用 jwt.io 解码了令牌,它绝对不是空的。它包含 14 个声明。 aud、iss、tid 等...
然后我在此请求中使用访问令牌
GET https://graph.microsoft.com/v1.0/users
Athorization: Bearer eyJ0eX...
然后我得到一个 401 Unauthorized with this body:
{
"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token is empty.",
"innerError": {
"request-id": "",
"date": "2018-08-14T15:41:44"
}
}
}
预期结果是 200 Ok,正文包含用户列表
这是否仅仅意味着我的应用未经授权,错误消息只是误导(访问令牌为空)? 还是我做错了什么?
更新: 我注意到虽然令牌确实包含声明,但它没有范围声明,这对我来说似乎有点奇怪。我会假设它有 User.Read.All 范围。应用程序(客户端 id/client 秘密)应具有此权限。 我收到的令牌中的声明具有以下声明:
aud: "<a href="https://graph.microsoft.com" rel="nofollow noreferrer">https://graph.microsoft.com</a>",
iss: "<a href="https://sts.windows.net/my" rel="nofollow noreferrer">https://sts.windows.net/my</a> tennant id",
iat: timestamp
nbf: timestamp
exp: timestamp
aio: looks like some kind of signature
app_displayname: "the expected app name"
appid: "the expected appid"
appidacr: "1"
idp: "<a href="https://sts.windows.net/" rel="nofollow noreferrer">https://sts.windows.net/</a>...."
oid: "GUID"
sub: "GUID"
tid: "my tennant id"
uti: "value"
ver: 1.0
</pre>
授权 header 拼写错误。
所以 "Access token is empty" 可能实际上意味着不存在甚至 "No authorization header in request"。
对于 User.Read.All 范围,您无法获得用户同意。必须征得管理员同意。看起来您可能没有使用管理员帐户同意您的应用程序。
要做到这一点:
GET https://login.microsoftonline.com/{tenant}/adminconsent
?client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&state=12345
&redirect_uri=http://localhost/myapp/permissions
然后获取访问令牌,您应该获取管理员已同意用户使用的范围。
一个 URL 有效,另一个无效。
这个有效:
endpoint = "https://graph.microsoft.com/v1.0/reports/getOffice365ActiveUserDetail%28period%3D%27D7%27%29"
headers = {"Authorization": 'Bearer ' + access_token_gmc}
response = requests.get(endpoint, headers=headers)
但是这个没有:
endpoint = "https://graph.microsoft.com/v1.0//users/myuserid/calendars"
headers = {"Authorization": 'Bearer ' + access_token_gmc}
response = requests.get(endpoint, headers=headers)
请确保拼写正确。
对我来说,我的问题是我在请求 url 和授权 header 之间设置了换行符,改为 body。
错误:
GET https://graph.microsoft.com/v1.0/users
Authorization: Bearer {{token}}
正确:
GET https://graph.microsoft.com/v1.0/users
Authorization: Bearer {{token}}
一个愚蠢的错误,但很容易被忽视 - 如果你遇到这个 post 你可能犯了一个愚蠢的错误,比如 OP(打字错误)或这个。再次查看您的请求语法!
我在使用 MSAL
.
angular
应用程序中遇到了同样的错误
而这一切都是因为MSALAngularConfigFactory
中提供的错误API scope
。我之前有 environment
。
export const environment = {
production: false,
clientId: 'clientid',
redirectUrl: 'http://localhost:4200',
graphApiUrl: 'https://graph.microsoft.com/v1.0',
graphGetUserImage: '/me/photo/$value',
protectedResourceMap: [
['http://localhost:65498/api', ['api.access']],
['https://graph.microsoft.com/beta', ['user.read']]
] as [string, string[]][],
authority: 'https://login.microsoftonline.com/organizations'
};
如您所见,我在 protectedResourceMap
中给出了 https://graph.microsoft.com/beta
,这是错误的。相反,我们应该给出 https://graph.microsoft.com/v1.0/
。所以这是正确的 environment
.
export const environment = {
production: false,
clientId: 'clientid',
redirectUrl: 'http://localhost:4200',
graphApiUrl: 'https://graph.microsoft.com/v1.0',
graphGetUserImage: '/me/photo/$value',
protectedResourceMap: [
['http://localhost:65498/api', ['api.access']],
['https://graph.microsoft.com/v1.0/', ['user.read']]
] as [string, string[]][],
authority: 'https://login.microsoftonline.com/organizations'
};
我在 app.module.ts
中使用它,如下所示。
function MSALAngularConfigFactory(): MsalAngularConfiguration {
return {
popUp: false,
protectedResourceMap: environment.protectedResourceMap,
};
}