如何配置Keycloak实现Private Key JWT认证?
Keycloak本地配置Private Key JWT认证及Java实现示例
一、Keycloak客户端配置步骤
创建/配置OpenID Connect客户端
- 登录本地Keycloak控制台,进入目标Realm,点击「客户端」→「创建客户端」。
- 客户端类型选择
OpenID Connect,填写客户端ID(后续生成JWT时iss/sub字段需与该值一致),完成创建。 - 在客户端设置页,开启「客户端认证」,并将「认证方式」设置为
private_key_jwt。 - 访问类型选择
confidential,生产环境按需配置「有效重定向URI」,测试环境可临时填*。
上传公钥/证书
- 切换到客户端的「凭据」标签页,找到「公钥」输入框,粘贴你用于签名JWT的X509证书对应的PEM格式公钥(可去掉头尾标签和换行,直接粘贴纯Base64内容)。
- 若有完整证书文件,也可切换到「密钥」标签页,点击「导入证书」上传,Keycloak会自动提取公钥用于验证JWT签名。
二、Java生成Client Assertion(JWT)示例
使用JJWT库生成符合要求的client_assertion,以下是完整实现:
Maven依赖
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency>
生成代码
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.spec.PKCS8EncodedKeySpec; import java.util.Base64; import java.util.Date; import java.util.UUID; public class PrivateKeyJwtGenerator { public static String generateClientAssertion(String clientId, String tokenEndpoint) throws Exception { // 加载PKCS8格式的私钥PEM文件 String privateKeyPem = Files.readString(Paths.get("path/to/your/private-key.pem"), StandardCharsets.UTF_8); privateKeyPem = privateKeyPem.replace("-----BEGIN PRIVATE KEY-----", "") .replace("-----END PRIVATE KEY-----", "") .replaceAll("\\s", ""); // 解析私钥 byte[] keyBytes = Base64.getDecoder().decode(privateKeyPem); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(spec); // 构建并签名JWT long now = System.currentTimeMillis(); return Jwts.builder() .setIssuer(clientId) // iss: 客户端ID .setAudience(tokenEndpoint) // aud: Keycloak的Token端点URL .setSubject(clientId) // sub: 客户端ID .setIssuedAt(new Date(now)) .setExpiration(new Date(now + 30 * 1000)) // 30秒过期,按需调整 .setId(UUID.randomUUID().toString()) // jti: 唯一标识 .signWith(privateKey, SignatureAlgorithm.RS256) .compact(); } public static void main(String[] args) throws Exception { String clientAssertion = generateClientAssertion( "your-client-id", "http://localhost:8080/realms/your-realm/protocol/openid-connect/token" ); System.out.println("Client Assertion: " + clientAssertion); } }
三、调用Keycloak Token接口获取认证Token
发送POST请求到Keycloak的Token端点,参数如下:
- URL:
http://localhost:8080/realms/your-realm/protocol/openid-connect/token - 请求头:
Content-Type: application/x-www-form-urlencoded - 表单参数:
grant_type=client_credentials client_id=your-client-id client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer client_assertion=生成的JWT字符串
内容的提问来源于stack exchange,提问作者Tech Savy
相关产品推荐
相关产品推荐

