Microsoft Graph:如何在客户端凭据流中获取带有证书的访问令牌? (而不是使用 client_secret)
Microsoft Graph: How to get access token with certificate in client credentials flow? (instead of using a client_secret)
目标
我想使用证书而不是针对 Microsoft Graph 的客户端密码来验证我的守护程序应用程序,并且想了解成功验证所需的确切请求。
使用以下资源:
- https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#second-case-access-token-request-with-a-certificate
https://docs.microsoft.com/en-us/graph/auth-v2-service
- https://laurakokkarinen.com/authenticating-to-office-365-apis-with-a-certificate-step-by-step/
- https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-OAPX/%5BMS-OAPX%5D.pdf
您的应用程序的 Azure AD 配置是否有错误?
所有 Azure AD 配置都在 client-secret
之前进行了测试。
证书 public 密钥也已预先上传:
请求与问题
我设法创建了这个请求(tenant-id,client-id,证书只是假人)
值:
grant_type
: urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertion_type
: logon_cert
client_id
: my-client-id-from-azure
scope
: https://graph.microsoft.com/.default
client_assertion
: JWT 包含
Header:(x5t 包含来自上传证书的 base64 编码证书 sha1 指纹,见上图)
{
"typ": "JWT",
"x5t": "QUY4RjBERERGMDBBOURGRUQ0MzkzODRGQTYzMjhFQ0FBRDNBOEUzNw",
"alg": "RS256"
}
有效载荷:
{
"iss": "my-client-id-from-azure",
"sub": "my-client-id-from-azure",
"scope": "https://graph.microsoft.com/.default",
"aud": "https://login.microsoftonline.com/my-tenant-id/oauth2/v2.0/token",
"iat": 1625591612,
"nbf": 1625591612,
"exp": 1625595212,
"jti": "some-dynamically-generated-uuid"
}
要求:
POST https://login.microsoftonline.com/my-tenant-id/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=eyJ0eXAiOiJKV1QiLCJ4NXQiOiJSRFUwTUVRd016RkdOakpGTUVOQk5UaEVPVFpGTXpBNFFrRkZNMFUzTmpFd01USkVPRFUwUWc9PSIsImFsZyI6IlJTMjU2In0.eyJpc3MiOiJteS1jbGllbnQtaWQtZnJvbS1henVyZSIsInNjb3BlIjoiaHR0cHM6Ly9ncmFwaC5taWNyb3NvZnQuY29tLy5kZWZhdWx0IiwiYXVkIjoiaHR0cHM6Ly9sb2dpbi5taWNyb3NvZnRvbmxpbmUuY29tL215LXRlbmFudC1pZC9vYXV0aDIvdjIuMC90b2tlbiIsImlhdCI6MTYyNTY2MDU3MywibmJmIjoxNjI1NjYwNTczLCJzdWIiOiJteS1jbGllbnQtaWQtZnJvbS1henVyZSIsImp0aSI6IjlhZTQwYTk2LTliMTgtNDRhOS1hOWM3LWE3NDZjMjA4OGUxMyIsImV4cCI6MTYyNTY2NDE3M30.pw81FeQirjIsnXGlLSLDG5Cz4rIdOuF54M8fPmDlubNs0-DoHpkj9OdrCXlCPDWvQLaYAs3mH9kcSP-Z4rf-NgaiCF-ECL-iA2xxvQ3n8JSDeaPPkLd6tMAKeMm5sEIcap7RJ8Fnt1kCflVAOIuYCh_zijJd9etQj-2wfbtiHnHtlpg6n0-4u7oj9wAx2naIU6J4dtgdIPypBTfwxyXtZWy0nkM8jde6Jr7CqVVlECdf7wyGwN1Jhwf6PeihKn8peQKaXzVnMmLpcCmjNENnTRM5PmhEQkCGOOR4hMJkdfCONWmOtSoRlndhCQypBQM-fzl_-sDviXNjAYKvrYTUM-kwZZBqKyzdekqMnxxwnaKmF1uGVnrSjad_AfW0A9Vg9UpaqGvsbe8Doq15I7KE46kzd4y3fDoibDQG-qaYL8LYKcrVUDkTw_PNfiyihlcaGjBvHVaMBsYhJJlNnohktO0OES0WO0iUlj_M0PuOF7JxYsPAQZM5uZGPTRCQhen_8khQ8z70C2YYz965kCROL9-WC53Ezbt1R0QjHR4UupV3CtQfZe_BkTG8vYu7SMWbxDEGZKb6cRsTCgzqmd6l3f6OGojQA_EAvFJpL0kw0d_tfYnY4ZkyLdcI3G3fMyhicm7qmkiq7ZRdnGL2uCl-tpxsoLD7UbvVPD3CS_LNAp4&client_id=my-client-id-from-azure&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&grant_type=client_credentials
响应:
我期待一个访问令牌,相反,我得到一个 401 Unauthorized
声明
{
"error": "invalid_client",
"error_description": "AADSTS700027: Client assertion contains an invalid signature. [Reason - The key was not found., Thumbprint of key used by client: 'some-other-thumbprint', Please visit the Azure Portal, Graph Explorer or directly use MS Graph to see configured keys for app Id 'my-app-id'. Review the documentation at https://docs.microsoft.com/en-us/graph/deployments to determine the corresponding service endpoint and https://docs.microsoft.com/en-us/graph/api/application-get?view=graph-rest-1.0&tabs=http to build a query request URL, such as 'https://graph.microsoft.com/beta/applications/my-app-id']\r\nTrace ID: some-uuid\r\nCorrelation ID: some-other-uuid\r\nTimestamp: 2021-07-07 12:25:46Z",
"error_codes": [
700027
],
"timestamp": "2021-07-06 12:25:46Z",
"trace_id": "some-uuid",
"correlation_id": "some-other-uuid",
"error_uri": "https://login.microsoftonline.com/error?code=700027"
}
我不知道问题是什么。
问题:
我做错了什么?
所以问题出在 x5t
header 的创建方式上。
我误解了在编码之前将指纹明确声明为 hex
的文档 base64
:
对于像这样的指纹 204C837E10143C1428D7911CB60ED0075C3E1062
,字符串需要被视为 HEX 二进制,而不是简单的字符串。
示例 (PHP):
伪代码:
// load certificate
certificate = load_file('/path/to/cert.pem')
// fingerprint is hex string 204C837E10143C1428D7911CB60ED0075C3E1062
certificate_fingerprint_hex_string = x509fingerprint($certificate)
// hexademical string is being converted to binary format
certificate_fingerprint_binary = hex_to_binary(certificate_fingerprint_hex_string)
// binary format gets base64 encoded (not base64url) to IEyDfhAUPBQo15Ectg7QB1w+EGI=
x5t = base64_encode(certificate_fingerprint_binary)
请求(Documentation)
Method
和 headers
POST https://login.microsoftonline.com/my-tenant-id/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Body(尚未根据 Content-Type 格式化)
client_id
: my-client-id-from-azure
client_assertion_type
: urn:ietf:params:oauth:client-assertion-type:jwt- bearer
client_assertion
:见下文 一个 JWT click here for details
grant_type
: client_credentials
scope
: https://graph.microsoft.com/.default
client_assertion
Header:(x5t
包含来自上传证书的 base64 编码证书 sha1 指纹,见上图)
{
"typ": "JWT",
"x5t": "IEyDfhAUPBQo15Ectg7QB1w+EGI=",
"alg": "RS256"
}
有效负载:
{
"iss": "my-client-id-from-azure",
"sub": "my-client-id-from-azure",
"scope": "https://graph.microsoft.com/.default",
"aud": "https://login.microsoftonline.com/my-tenant-id/oauth2/v2.0/token",
"iat": 1625591612,
"nbf": 1625591612,
"exp": 1625595212,
"jti": "some-dynamically-generated-uuid"
}
目标
我想使用证书而不是针对 Microsoft Graph 的客户端密码来验证我的守护程序应用程序,并且想了解成功验证所需的确切请求。
使用以下资源:
- https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#second-case-access-token-request-with-a-certificate
https://docs.microsoft.com/en-us/graph/auth-v2-service- https://laurakokkarinen.com/authenticating-to-office-365-apis-with-a-certificate-step-by-step/
- https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-OAPX/%5BMS-OAPX%5D.pdf
您的应用程序的 Azure AD 配置是否有错误?
所有 Azure AD 配置都在 client-secret
之前进行了测试。
证书 public 密钥也已预先上传:
请求与问题
我设法创建了这个请求(tenant-id,client-id,证书只是假人)
值:
grant_type
: urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertion_type
: logon_cert
client_id
: my-client-id-from-azure
scope
: https://graph.microsoft.com/.default
client_assertion
: JWT 包含
Header:(x5t 包含来自上传证书的 base64 编码证书 sha1 指纹,见上图)
{ "typ": "JWT", "x5t": "QUY4RjBERERGMDBBOURGRUQ0MzkzODRGQTYzMjhFQ0FBRDNBOEUzNw", "alg": "RS256" }
有效载荷:
{ "iss": "my-client-id-from-azure", "sub": "my-client-id-from-azure", "scope": "https://graph.microsoft.com/.default", "aud": "https://login.microsoftonline.com/my-tenant-id/oauth2/v2.0/token", "iat": 1625591612, "nbf": 1625591612, "exp": 1625595212, "jti": "some-dynamically-generated-uuid" }
要求:
POST https://login.microsoftonline.com/my-tenant-id/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=eyJ0eXAiOiJKV1QiLCJ4NXQiOiJSRFUwTUVRd016RkdOakpGTUVOQk5UaEVPVFpGTXpBNFFrRkZNMFUzTmpFd01USkVPRFUwUWc9PSIsImFsZyI6IlJTMjU2In0.eyJpc3MiOiJteS1jbGllbnQtaWQtZnJvbS1henVyZSIsInNjb3BlIjoiaHR0cHM6Ly9ncmFwaC5taWNyb3NvZnQuY29tLy5kZWZhdWx0IiwiYXVkIjoiaHR0cHM6Ly9sb2dpbi5taWNyb3NvZnRvbmxpbmUuY29tL215LXRlbmFudC1pZC9vYXV0aDIvdjIuMC90b2tlbiIsImlhdCI6MTYyNTY2MDU3MywibmJmIjoxNjI1NjYwNTczLCJzdWIiOiJteS1jbGllbnQtaWQtZnJvbS1henVyZSIsImp0aSI6IjlhZTQwYTk2LTliMTgtNDRhOS1hOWM3LWE3NDZjMjA4OGUxMyIsImV4cCI6MTYyNTY2NDE3M30.pw81FeQirjIsnXGlLSLDG5Cz4rIdOuF54M8fPmDlubNs0-DoHpkj9OdrCXlCPDWvQLaYAs3mH9kcSP-Z4rf-NgaiCF-ECL-iA2xxvQ3n8JSDeaPPkLd6tMAKeMm5sEIcap7RJ8Fnt1kCflVAOIuYCh_zijJd9etQj-2wfbtiHnHtlpg6n0-4u7oj9wAx2naIU6J4dtgdIPypBTfwxyXtZWy0nkM8jde6Jr7CqVVlECdf7wyGwN1Jhwf6PeihKn8peQKaXzVnMmLpcCmjNENnTRM5PmhEQkCGOOR4hMJkdfCONWmOtSoRlndhCQypBQM-fzl_-sDviXNjAYKvrYTUM-kwZZBqKyzdekqMnxxwnaKmF1uGVnrSjad_AfW0A9Vg9UpaqGvsbe8Doq15I7KE46kzd4y3fDoibDQG-qaYL8LYKcrVUDkTw_PNfiyihlcaGjBvHVaMBsYhJJlNnohktO0OES0WO0iUlj_M0PuOF7JxYsPAQZM5uZGPTRCQhen_8khQ8z70C2YYz965kCROL9-WC53Ezbt1R0QjHR4UupV3CtQfZe_BkTG8vYu7SMWbxDEGZKb6cRsTCgzqmd6l3f6OGojQA_EAvFJpL0kw0d_tfYnY4ZkyLdcI3G3fMyhicm7qmkiq7ZRdnGL2uCl-tpxsoLD7UbvVPD3CS_LNAp4&client_id=my-client-id-from-azure&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&grant_type=client_credentials
响应:
我期待一个访问令牌,相反,我得到一个 401 Unauthorized
声明
{
"error": "invalid_client",
"error_description": "AADSTS700027: Client assertion contains an invalid signature. [Reason - The key was not found., Thumbprint of key used by client: 'some-other-thumbprint', Please visit the Azure Portal, Graph Explorer or directly use MS Graph to see configured keys for app Id 'my-app-id'. Review the documentation at https://docs.microsoft.com/en-us/graph/deployments to determine the corresponding service endpoint and https://docs.microsoft.com/en-us/graph/api/application-get?view=graph-rest-1.0&tabs=http to build a query request URL, such as 'https://graph.microsoft.com/beta/applications/my-app-id']\r\nTrace ID: some-uuid\r\nCorrelation ID: some-other-uuid\r\nTimestamp: 2021-07-07 12:25:46Z",
"error_codes": [
700027
],
"timestamp": "2021-07-06 12:25:46Z",
"trace_id": "some-uuid",
"correlation_id": "some-other-uuid",
"error_uri": "https://login.microsoftonline.com/error?code=700027"
}
我不知道问题是什么。
问题:
我做错了什么?
所以问题出在 x5t
header 的创建方式上。
我误解了在编码之前将指纹明确声明为 hex
的文档 base64
:
对于像这样的指纹 204C837E10143C1428D7911CB60ED0075C3E1062
,字符串需要被视为 HEX 二进制,而不是简单的字符串。
示例 (PHP):
伪代码:
// load certificate
certificate = load_file('/path/to/cert.pem')
// fingerprint is hex string 204C837E10143C1428D7911CB60ED0075C3E1062
certificate_fingerprint_hex_string = x509fingerprint($certificate)
// hexademical string is being converted to binary format
certificate_fingerprint_binary = hex_to_binary(certificate_fingerprint_hex_string)
// binary format gets base64 encoded (not base64url) to IEyDfhAUPBQo15Ectg7QB1w+EGI=
x5t = base64_encode(certificate_fingerprint_binary)
请求(Documentation)
Method
和 headers
POST https://login.microsoftonline.com/my-tenant-id/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Body(尚未根据 Content-Type 格式化)
client_id
:my-client-id-from-azure
client_assertion_type
:urn:ietf:params:oauth:client-assertion-type:jwt- bearer
client_assertion
:见下文 一个 JWT click here for detailsgrant_type
:client_credentials
scope
:https://graph.microsoft.com/.default
client_assertion
Header:(
x5t
包含来自上传证书的 base64 编码证书 sha1 指纹,见上图){ "typ": "JWT", "x5t": "IEyDfhAUPBQo15Ectg7QB1w+EGI=", "alg": "RS256" }
有效负载:
{ "iss": "my-client-id-from-azure", "sub": "my-client-id-from-azure", "scope": "https://graph.microsoft.com/.default", "aud": "https://login.microsoftonline.com/my-tenant-id/oauth2/v2.0/token", "iat": 1625591612, "nbf": 1625591612, "exp": 1625595212, "jti": "some-dynamically-generated-uuid" }