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

LinkedIn Access Token兑换Keycloak Token时出现400 invalid_token错误求助

Keycloak集成LinkedIn时Token Exchange返回invalid_token的问题排查

问题背景

我正在为使用Keycloak做认证的应用集成LinkedIn注册/登录功能,已实现以下流程:

  • 前端重定向至LinkedIn登录;
  • LinkedIn携带授权码重定向至后端回调接口;
  • 后端用授权码兑换LinkedIn Access Token并获取用户信息;
  • 后端在Keycloak中手动创建关联LinkedIn联邦身份(federated identity)的用户;
  • 调用Keycloak的Token Exchange API将LinkedIn Token转为Keycloak JWT。

相关代码

回调处理逻辑

public JwtTokenResponse processOAuthCallbackAndGetToken(String code) {
    // Step 1: Exchange authorization code for an access token
    String accessToken = exchangeAuthorizationCodeForAccessToken(code);

    // Step 2: Fetch user info from LinkedIn
    Map<String, Object> userInfo = fetchLinkedInUserProfile(accessToken);

    // Step 3: Create users in app
    if (userInfo == null) {
      throw new SomeException("Error occurred while fetching user info from LinkedIn.");
    }

    String email = (String) userInfo.get("email");
    // create user in the application if needed

    // Step 4: Create user in keycloak with federatedIdentity
    log.info("User Info from LinkedIn ::: {}", userInfo);
    Map<String, Object> federatedIdentity = new HashMap<>();
    federatedIdentity.put("identityProvider", "linkedin");
    federatedIdentity.put("userId", userInfo.get("sub")); // LinkedIn user ID
    federatedIdentity.put("userName", email);

    userService.createKeycloakUserWithFederatedIdentity(agentByEmail.getUser(), federatedIdentity);

    log.info("Created user in keycloak with federated identity ::: {}", federatedIdentity);

    // Step 5: Exchange LinkedIn access_token with jwt
    return keycloakAuthServerConnector.getTokenFromLinkedInAccessToken(accessToken);
}

Token Exchange调用逻辑

....
private static final String GRANT_TYPE_OAUTH_TOKEN_EXCHANGE =
    "urn:ietf:params:oauth:grant-type:token-exchange";
private static final String REQUESTED_TOKEN_TYPE =
    "urn:ietf:params:oauth:token-type:access_token";
public static final String PROTOCOL_OPENID_CONNECT_TOKEN = "/protocol/openid-connect/token";

public com.agencyheight.dto.onboardingv2.auth.JwtTokenResponse getTokenFromLinkedInAccessToken(
      String accessToken) {
    log.info("Requesting token with linkedIn access token :: {}", accessToken);

    return webClient
        .post()
        .uri(PROTOCOL_OPENID_CONNECT_TOKEN)
        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
        .body(
            BodyInserters.fromFormData("client_id", clientId)
                .with("client_secret", clientSecret)
                .with("grant_type", GRANT_TYPE_OAUTH_TOKEN_EXCHANGE)
                .with("subject_token", accessToken)
                .with("subject_issuer", "linkedin")
                .with("requested_token_type", REQUESTED_TOKEN_TYPE))
        .retrieve()
        .bodyToMono(com.agencyheight.dto.onboardingv2.auth.JwtTokenResponse.class)
        .block();
}

错误信息

{
    "error": "invalid_token",
    "error_description": "invalid token"
}

已在Keycloak中添加LinkedIn身份提供商配置,并按官方文档开启Token Exchange权限及设置策略,但仍出现该错误,请问遗漏了什么配置或导致错误的原因是什么?


排查方案及解决办法

1. 联邦身份的用户ID字段错误

LinkedIn用户信息接口返回的用户唯一标识是id字段,而非sub。代码中使用userInfo.get("sub")作为联邦身份的userId,会导致Keycloak无法匹配LinkedIn的用户身份,进而判定token无效。

  • 修复代码:将federatedIdentity.put("userId", userInfo.get("sub"));改为federatedIdentity.put("userId", userInfo.get("id"));

2. Token Exchange请求缺少subject_token_type参数

Keycloak的Token Exchange需要明确指定subject_token的类型,LinkedIn的access token属于urn:ietf:params:oauth:token-type:access_token类型,缺少该参数会导致验证失败。

  • 修复请求:在表单参数中添加
    .with("subject_token_type", "urn:ietf:params:oauth:token-type:access_token")
    

3. Keycloak身份提供商配置验证

  • 确认LinkedIn身份提供商的Alias设置为linkedin,需与代码中subject_issuer的值完全一致;
  • 开启身份提供商的验证令牌选项(配置标签页),Keycloak需要验证LinkedIn access token的有效性,未开启则直接判定token无效。

4. LinkedIn Access Token权限范围不足

确保前端跳转LinkedIn时请求的scope包含openid email profile,缺少这些权限会导致LinkedIn返回的token无法被Keycloak验证通过。

5. 客户端Token Exchange权限检查

  • 确认调用Token Exchange的客户端(代码中的client_id)已启用urn:ietf:params:oauth:grant-type:token-exchange授权类型;
  • 在客户端的"权限"设置中,添加token-exchange权限并启用。

内容的提问来源于stack exchange,提问作者Sabu Shakya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 19:37:13