使用Microsoft.Identity.Web的Azure B2C授权码流未返回Access/Refresh Token
问题描述
我正尝试将IdentityServer4应用的认证/授权迁移至Azure B2C,但遇到了以下问题:
- 按照官方指引拦截
OnTicketReceived事件以扩展业务域声明,已将ResponseType设置为授权码流的"code id_token",但该设置被忽略,响应仅返回id_token。 - 查看发送至AAD B2C的OIDC消息,发现scope为
"openid profile offline_access",ResponseType为"code",而非我指定的"code id_token"。 - 从示例来看需在控制器方法中通过注入的
ITokenAcquisitionAPI请求access token,我可以重构代码实现这一点,但疑惑为何在Startup类中指定的授权码流完全不生效,是否误解了Microsoft.Identity.Web的工作机制?
原因分析与解决方案
1. Microsoft.Identity.Web的默认行为
Microsoft.Identity.Web针对Web应用场景做了封装,默认会覆盖手动设置的ResponseType:
- 当仅配置Web应用身份验证(未关联API访问)时,框架默认使用授权码流(
ResponseType="code"),且只会获取ID Token用于用户认证,不会自动请求Access Token。 - 你设置的
"code id_token"属于混合流,但Microsoft.Identity.Web在纯Web应用场景下不推荐这种模式,框架内部会自动调整为符合最佳实践的授权码流配置。
2. 关于Scope的问题
默认的"openid profile offline_access"是Web应用认证的基础Scope:
openid:表明是OIDC认证流程,必须包含;profile:用于获取用户基本信息;offline_access:用于获取刷新令牌,支持持久化登录。
若需要获取Access Token访问API,必须显式添加对应的API Scope(比如https://yourtenant.onmicrosoft.com/api/access_as_user)。
3. 让授权码流生效并获取Access Token的正确方式
要在Startup中配置自动获取Access Token,需使用Microsoft.Identity.Web的AddWebAppCallsWebApi扩展方法,而非单纯的AddAuthentication+AddOpenIdConnect:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAdB2C")) .EnableTokenAcquisitionToCallDownstreamApi(new[] { "your-api-scope" }) .AddInMemoryTokenCaches();
配置后,框架会自动处理授权码流,获取ID Token和Access Token,同时你仍可在OnTicketReceived事件中扩展用户声明:
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options => { options.Events.OnTicketReceived = context => { // 扩展业务域声明逻辑 var claimsIdentity = context.Principal.Identity as ClaimsIdentity; claimsIdentity.AddClaim(new Claim("custom-claim", "custom-value")); return Task.CompletedTask; }; });
4. 若需使用混合流(不推荐)
如果确实有特殊场景需要使用混合流,需覆盖Microsoft.Identity.Web的默认配置,在AddMicrosoftIdentityWebApp后手动设置:
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options => { options.ResponseType = "code id_token"; // 同时添加对应的API Scope options.Scope.Add("your-api-scope"); });
但这种方式不符合框架设计初衷,易引发后续兼容问题,建议优先使用EnableTokenAcquisitionToCallDownstreamApi的标准方式。
内容的提问来源于stack exchange,提问作者jcaddy
相关产品推荐
相关产品推荐

