You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在登出时获取持久化的id_token?(Okta+.NET6+IS4场景)

问题:登出时无法获取Okta的id_token

我当前使用Okta、.NET 6和Identity Server 4(计划升级到6.0),需要用id_token完成Okta的登出操作,但登出时该值始终为null。登录时已确认id_token被添加到Claims中,但登出时context.HttpContext.User.FindFirst("id_token")和context.Properties.GetTokenValue("id_token")都返回null,且此时用户声明中仅存在idp: local。

核心原因

登出时的HttpContext.User是Identity Server的本地用户身份,而非Okta外部登录的身份;同时手动存储token的逻辑与SaveTokens=true的自动存储冲突,且未关联到外部登录的认证上下文。

解决方案

1. 移除手动存储token的冗余代码

已配置options.SaveTokens = true,OpenIdConnect中间件会自动将id_token、access_token等保存到外部登录Cookie(idsrv.external)的AuthenticationProperties中,无需手动调用StoreTokens:

private Task OnTokenResponseReceivedImpl(TokenResponseReceivedContext context)
{
    // 移除手动存储token的代码,依赖SaveTokens=true自动处理
    return Task.CompletedTask;
}

2. 调整登出事件逻辑,从外部登录上下文获取id_token

登出时通过AuthenticateAsync获取外部登录的认证结果,从中提取id_token:

private async Task OnRedirectToIdentityProviderForSignOutImpl(RedirectContext context)
{
    var oidcMessage = context.ProtocolMessage;
    
    // 获取Okta外部登录的认证上下文
    var externalAuthResult = await context.HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
    if (externalAuthResult.Succeeded)
    {
        // 从外部登录的Properties中提取id_token
        var idTokenClaim = externalAuthResult.Properties.GetTokenValue("id_token");
        if (idTokenClaim != null)
        {
            oidcMessage.IdTokenHint = idTokenClaim;
            oidcMessage.PostLogoutRedirectUri = HomeUrl.AbsoluteUri;
        }
    }
    // ...其他登出逻辑
}

3. 确保登出流程触发外部身份提供商的登出

在发起登出的代码中,同时触发Identity Server和Okta的登出:

// 登出Identity Server本地会话
await HttpContext.SignOutAsync(IdentityServerConstants.SignoutScheme);
// 触发Okta的登出流程
await HttpContext.SignOutAsync("oidc");

可选:在ProfileService中持久化id_token到本地用户声明

如果需要在本地用户身份中始终保留id_token,可以在Identity Server的IProfileService实现中添加该声明,确保登出时本地用户也能直接获取:

public class CustomProfileService : IProfileService
{
    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        // 从外部登录的认证信息中获取id_token(如果存在)
        var externalAuth = await context.HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
        if (externalAuth.Succeeded)
        {
            var idToken = externalAuth.Properties.GetTokenValue("id_token");
            if (idToken != null)
            {
                context.IssuedClaims.Add(new Claim("id_token", idToken));
            }
        }
        // ...其他Profile逻辑
    }

    // ...实现IsActiveAsync方法
}

然后注册该ProfileService:

services.AddIdentityServer()
    .AddProfileService<CustomProfileService>()
    // ...其他Identity Server配置

内容的提问来源于stack exchange,提问作者David Klempfner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 14:50:36