使用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的示例,但可以参考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

