如何验证Microsoft jwt id_令牌?

如何验证Microsoft jwt id_令牌?,jwt,jose,microsoft-identity-platform,Jwt,Jose,Microsoft Identity Platform,我正在使用来自Microsoft的jwt令牌对客户端进行验证,以验证从客户端到web API(服务器)的请求。我可以控制客户端(js)和服务器(Python)的代码 在客户端,我使用以下请求获取令牌(用户通过租户上的password/2FA声明): 这里guid是一个唯一的值,TENANT\u ID是租户,CLIENT\u ID是客户端 获取此令牌后,我将其作为授权标头发送,如下所示: init = { headers: { 'Authorization': `Bearer

我正在使用来自Microsoft的jwt令牌对客户端进行验证,以验证从客户端到web API(服务器)的请求。我可以控制客户端(js)和服务器(Python)的代码

在客户端,我使用以下请求获取令牌(用户通过租户上的password/2FA声明):

这里
guid
是一个唯一的值,
TENANT\u ID
是租户,
CLIENT\u ID
是客户端

获取此令牌后,我将其作为授权标头发送,如下所示:

init = {
    headers: {
       'Authorization': `Bearer ${token}`,
    }
}

return fetch(url, init).then(response => {
    return response.json()
})
然后在服务器上检索令牌并验证它:

if 'Authorization' in request.headers and request.headers['Authorization'].startswith('Bearer '):
    token = request.headers['Authorization'][len('Bearer '):]
    from authlib.jose import jwt
    claims = jwt.decode(token, jwk)
其中
jwk
https://login.microsoftonline.com/{TENANT_ID}/discovery/v2.0/keys

整个流程一直工作到验证,验证失败,出现以下错误:

authlib.jose.errors.InvalidHeaderParameterName: invalid_header_parameter_name: Invalid Header Parameter Names: nonce
这表示令牌的头包含一个键
nonce
(我验证了它)

查看微软关于这一点的文档,在标题上没有提到一个
nonce
,只是在有效负载上

问题1:我做错了什么

问题2:假设Microsoft将nonce放在了错误的位置(标头而不是有效负载),那么在将其传递到jose的身份验证库之前,是否可以从标头(服务器端)中删除nonce?这样做安全吗?

请参阅:

以下是我在API中验证Azure AD Id_令牌的方法:

导入base64
进口jwt
从cryptography.hazmat.primitives.asymetric.rsa导入公共数字
从cryptography.hazmat.backends导入默认\u后端
从cryptography.hazmat.primitives导入序列化
def确保_字节(密钥):
如果isinstance(键,str):
key=key.encode('utf-8')
返回键
def解码_值(val):
decoded=base64.urlsafe\u b64解码(确保字节(val)+b'=')
返回int.from_字节(解码为“大”)
来自jwk(jwk)的def rsa_pem_:
返回公共号码(
n=解码_值(jwk['n']),
e=解码_值(jwk['e'])
).public_key(默认_backend()).public_字节(
encoding=serialization.encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
#根据需要获取jwks:配置文件,HTTP GET请求,发送给返回jwks的端点;
jwks={
“钥匙”:[
{
“kty”:“RSA”,
“使用”:“sig”,
“孩子”:“piVlloQDSMKx…”,
“x5t”:“piVlloQDSMKx…”,
“n”:“0xHHHWPMEPN jDBapnzhF…”,
“e”:“AQAB”,
“x5c”:[
“MIIDBTCAE2GAWIBAGIQMCJCG…”
],
“发行人”:https://login.microsoftonline.com/{租户}/v2.0“
}
]
}
#配置,这些可以在Azure B2C的有效JWT中看到:
有效的_受众=['dd050a67-ebfd-xxx-xxxx-xxxxxxxx']#先前准备的应用程序id
类InvalidAuthorizationToken(异常):
定义初始(自我,详细信息):
超级()
def get_kid(代币):
headers=jwt.get\u unverified\u头(令牌)
如果不是标题:
引发InvalidAuthorizationToken('缺少标题')
尝试:
返回标题['kid']
除KeyError外:
引发InvalidAuthorizationToken('失踪的孩子')
def get_jwk(儿童):
对于jwks.get中的jwk('keys'):
如果jwk.get('kid')==kid:
返回jwk
引发InvalidAuthorizationToken('未识别的孩子')
def get_发卡机构(儿童):
对于jwks.get中的jwk('keys'):
如果jwk.get('kid')==kid:
返回jwk.get('issuer')
引发InvalidAuthorizationToken('未识别的孩子')
def get_公钥(令牌):
从_jwk返回rsa_pem_(get_jwk(get_kid(token)))
def validate_jwt(jwt_至_validate):
尝试:
公钥=获取公钥(jwt-to-validate)
发行人=获得发行人(儿童)
选项={
“验证签名”:True,
“验证_exp”:True,#跳过过期日期检查
“verify_nbf”:False,
“验证”:False,
“验证aud”:为真,跳过观众检查
}
解码=jwt.decode(jwt\u至\u验证,
公钥,
选项=选项,
算法=['RS256'],
受众=有效的受众,
发卡机构=发卡机构)
#使用解码的令牌执行您希望的操作:
#如果我们到了这里,JWT就被验证了
打印(解码)
例外情况除外,例如:
打印('JWT无效!')
返回错误
其他:
返回解码
打印('JWT有效!')

是,但我如何才能为我的租户获得jwks???@chatzich请参阅格式:
https://{tenant\u name}.b2clogin.com/{tenant\u name}.onmicrosoft.com/{policy\u name}/discovery/v2.0/keys
例如:
https://contoso.b2clogin.com/contoso.onmicrosoft.com/b2c_1_signupsignin1/discovery/v2.0/keys
authlib.jose.errors.InvalidHeaderParameterName: invalid_header_parameter_name: Invalid Header Parameter Names: nonce