Azure AD B2C违反OIDC规范致API Gateway JWT授权器配置报错
我参考官方文档完成AAD B2C IEF自定义策略配置后,尝试按照AWS官方指引将其作为JWT授权器接入API Gateway,配置授权器环节抛出以下错误:
error updating API Gateway v2 authorizer
BadRequestException
Caught exception when connecting tohttps://tenant-domain.b2clogin.com/tenant-id-here/v2.0/.well-known/openid-configurationfor issuerhttps://tenant-domain.b2clogin.com/tenant-id-here/v2.0/.
Please try again later.
Error:
Invalid issuer:https://tenant-domain.b2clogin.com/tenant-id-here/v2.0/.
Issuer must have a valid discovery endpoint ended with '/.well-known/openid-configuration'
当前实际可正常访问的OIDC发现端点为https://tenant-domain.b2clogin.com/tenant-domain.onmicrosoft.com/b2c_1a_signup_signin/v2.0/.well-known/openid-configuration,但该端点返回的配置文档中issuer字段值和发现端点URL前缀不匹配,核心返回内容如下:
{ "issuer": "https://tenant-domain.b2clogin.com/tenant-id-here/v2.0/", "authorization_endpoint": "https://tenant-domain.b2clogin.com/tenant-domain.onmicrosoft.com/b2c_1a_signup_signin/oauth2/v2.0/authorize", "token_endpoint": "https://tenant-domain.b2clogin.com/tenant-domain.onmicrosoft.com/b2c_1a_signup_signin/oauth2/v2.0/token", "end_session_endpoint": "https://tenant-domain.b2clogin.com/tenant-domain.onmicrosoft.com/b2c_1a_signup_signin/oauth2/v2.0/logout", "jwks_uri": "https://tenant-domain.b2clogin.com/tenant-domain.onmicrosoft.com/b2c_1a_signup_signin/discovery/v2.0/keys", "response_modes_supported": ["query", "fragment", "form_post"], "response_types_supported": ["code", "code id_token", "code token", "code id_token token", "id_token", "id_token token", "token", "token id_token"], "scopes_supported": ["openid"], "subject_types_supported": ["pairwise"], "id_token_signing_alg_values_supported": ["RS256"], "token_endpoint_auth_methods_supported": ["client_secret_post", "client_secret_basic"], "claims_supported": ["name", "given_name", "family_name", "email", "sub", "tid", "iss", "iat", "exp", "aud", "acr", "nonce", "auth_time"] }
对照已知问题记录和OIDC官方规范,确认AAD B2C的该实现不符合OIDC规范要求,现咨询是否有可行的集成方案,是否必须更换符合OIDC规范的身份提供商。
不需要更换身份提供商,目前有两种经过生产验证的落地方案,按实施成本从低到高排列:
方案1:使用REST API + Lambda自定义授权器(无额外依赖)
HTTP API的原生JWT授权器会强制校验issuer值与发现端点的前缀匹配规则,没有提供跳过该校验的配置入口,而REST API的Lambda令牌授权器不会做这个强制校验,是成本最低的解决方式:
- 将接口承载类型切换为API Gateway REST API(如果不是必须用HTTP API的话)
- 编写Lambda授权器代码,手动实现JWT校验逻辑:
- 直接从B2C策略对应的JWKS端点拉取签名公钥,本地缓存公钥减少重复请求
- 校验JWT签名有效性、过期时间、受众(aud)、签发范围等基础字段
- 直接校验iss字段值是否为B2C返回的固定值
https://tenant-domain.b2clogin.com/tenant-id-here/v2.0/,不需要做iss到发现端点的拼接校验 - 校验通过后返回允许访问的IAM策略,校验失败直接返回401/403响应
- 整个Lambda逻辑可以直接复用成熟的开源JWT校验库实现,代码量通常在100行以内,不需要改动B2C侧任何配置。
方案2:部署OIDC发现代理(保留HTTP API原生授权器能力)
如果必须使用HTTP API的原生JWT授权器,不想维护自定义授权器的校验逻辑,可以部署一个轻量公网代理修正OIDC配置的issuer字段:
- 代理服务接收
/.well-known/openid-configuration请求时,直接转发到实际的B2C发现端点 - 将返回结果中的
issuer字段值修改为代理服务自身的域名对应路径,例如代理域名为https://auth-proxy.your-domain.com,就把issuer改为https://auth-proxy.your-domain.com/b2c_1a_signup_signin/v2.0/ - 其余字段(包括jwks_uri、各业务端点地址)全部透传,不需要修改
- 在API Gateway侧配置JWT授权器时,将issuer设置为修改后的值,发现端点地址填代理服务的OIDC发现地址即可
- 代理服务可以用CloudFront+Lambda@Edge、API Gateway+Lambda甚至静态CDN托管固定配置JSON实现,运行成本几乎可以忽略。
注意:不要尝试通过修改AAD B2C自定义策略的配置来覆盖issuer声明值,B2C服务端会强制重写该字段,自定义配置不会生效。
内容的提问来源于stack exchange,提问作者John B

