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

使用pac4j对接login.gov时,OidcAuthenticator.executeTokenRequest执行失败

问题描述

我使用pac4j对接login.gov,配置如下:

final OidcConfiguration oidcConfiguration = new OidcConfiguration();
oidcConfiguration.setClientId("urn:gov:noaa:openidconnect.profiles:dashboard:sso:pmel:oap");
oidcConfiguration.setClientAuthenticationMethod(ClientAuthenticationMethod.PRIVATE_KEY_JWT);
RSAPrivateKey privateKey = readPKCS8PrivateKey(new File("joe.key"));
var privateKeyJwtConfig = new PrivateKeyJWTClientAuthnMethodConfig(JWSAlgorithm.RS256, privateKey, "logingov");
oidcConfiguration.setPrivateKeyJWTClientAuthnMethodConfig(privateKeyJwtConfig);
oidcConfiguration.setUseNonce(true);
oidcConfiguration.setResponseType("code");
oidcConfiguration.setScope("openid");
oidcConfiguration.addCustomParam("acr_values", "http://idmanagement.gov/ns/assurance/ial/1");
oidcConfiguration.addCustomParam("prompt", "select_account");
oidcConfiguration.addCustomParam("client_assertion_type","urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
oidcConfiguration.setDiscoveryURI("https://idp.int.identitysandbox.gov/.well-known/openid-configuration");
oidcConfiguration.setWithState(true);
oidcConfiguration.setStateGenerator(new LoginGovStateGenerator());
oidcConfiguration.setPreferredJwsAlgorithm(JWSAlgorithm.RS256);
final OidcClient oidcClient = new OidcClient(oidcConfiguration);    
oidcClient.setName("logingov");
oidcClient.setSaveProfileInSession(true);
final Clients clients = new Clients("http://localhost:8182/SimpleServer/callback", oidcClient);
final DefaultSessionLogoutHandler defaultCasLogoutHandler = new DefaultSessionLogoutHandler();
Config config = new Config(clients);
defaultCasLogoutHandler.setDestroySession(true); 
config.setSessionLogoutHandler(defaultCasLogoutHandler);
return config

登录流程可正常获取授权码:

OidcCredentials(code=a3373a1b-fe76-4b3e-89e0-275dee7431d9, accessToken=null, refreshToken=null, idToken=null)

但使用授权码交换token时失败,报错:

Client assertion Nil JSON web token, description=null, status=400
    at org.pac4j.oidc.credentials.authenticator.OidcAuthenticator.executeTokenRequest(OidcAuthenticator.java:120)

仅在调试时手动向token请求添加client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer参数,才能继续流程。

请问:

  • 有没有pac4j对接login.gov的示例?
  • 配置中可能缺少什么?
  • 是否需要自定义OidcAuthenticator修复token请求?
排查与解决方案

1. 修正PrivateKeyJWT配置的Issuer参数

login.gov要求client_assertion的issuer(iss)和subject(sub)必须等于客户端ID。你当前的PrivateKeyJWTClientAuthnMethodConfig构造中,第三个参数设为了"logingov",这是错误的,需要替换为你的clientId值:

var privateKeyJwtConfig = new PrivateKeyJWTClientAuthnMethodConfig(JWSAlgorithm.RS256, privateKey, "urn:gov:noaa:openidconnect.profiles:dashboard:sso:pmel:oap");

2. 移除手动添加的client_assertion_type自定义参数

当设置ClientAuthenticationMethod.PRIVATE_KEY_JWT时,pac4j会自动在token请求中添加client_assertion_type和对应的client_assertion参数。手动添加该自定义参数可能导致逻辑冲突,或被pac4j的内置逻辑忽略。

3. 确保Audience配置正确(可选)

部分pac4j版本需要明确指定client_assertion的audience为login.gov的token端点。可以通过Discovery机制获取端点后设置:

// 先初始化discovery端点
oidcConfiguration.initDiscovery();
OidcDiscoveryEndpoint discoveryEndpoint = oidcConfiguration.getDiscoveryEndpoint();
// 为privateKeyJwtConfig设置audience
privateKeyJwtConfig.setAudience(discoveryEndpoint.getTokenEndpoint());

4. 自定义OidcAuthenticator(兜底方案)

如果上述配置仍未解决问题,可以自定义OidcAuthenticator,重写executeTokenRequest方法,确保token请求中正确携带所需参数:

public class CustomLoginGovOidcAuthenticator extends OidcAuthenticator {
    public CustomLoginGovOidcAuthenticator(OidcConfiguration configuration) {
        super(configuration);
    }

    @Override
    protected OidcToken executeTokenRequest(OidcCredentials credentials, WebContext context) {
        // 获取原请求参数
        Map<String, String> params = getTokenRequestParameters(credentials, context);
        // 手动添加必要参数(如果自动添加失效)
        params.put("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
        // 生成并添加client_assertion(可复用pac4j内置逻辑)
        String clientAssertion = generateClientAssertion(getConfiguration(), context);
        params.put("client_assertion", clientAssertion);
        // 执行请求
        return getTokenEndpointClient().postFormRequest(getConfiguration().getDiscoveryEndpoint().getTokenEndpoint(), params, OidcToken.class);
    }
}

然后在配置中替换默认的Authenticator:

oidcClient.setAuthenticator(new CustomLoginGovOidcAuthenticator(oidcConfiguration));
关于pac4j对接login.gov的示例

目前pac4j官方没有专门针对login.gov的示例,但可以参考OIDC Private Key JWT认证模式的通用配置逻辑,核心需满足login.gov的OIDC规范:

  • 使用PRIVATE_KEY_JWT客户端认证方式
  • client_assertion的iss/sub必须等于客户端ID
  • 签名算法与login.gov要求一致(RS256)
  • 正确配置acr_values等login.gov特定参数

内容的提问来源于stack exchange,提问作者Roland Schweitzer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 05:25:17