---
title: RP 密钥配置与轮换
description: 配置 private_key_jwt 和签名 OIDC 请求使用的公钥。
editUrl: true
head: []
template: doc
sidebar:
  order: 4
  hidden: false
  attrs: {}
pagefind: true
draft: false
---

RP 密钥用于在 `/token` 证明客户端身份，并验证客户端的签名 Request Object。它与签发 ID Token 的提供方密钥、签发 access token 的应用密钥分别配置。见[令牌验证](/zh-cn/concepts/tokens-and-verification/)。

## 选择密钥来源

| 来源 | 配置内容 | RP 保存的内容 |
|---|---|---|
| 平台 client-auth 密钥 | 为托管客户端选择平台密钥来源。 | 创建或轮换时提供的 client-auth 私钥。 |
| 内联 RP JWKS | 注册包含 RSA 签名公钥的 JSON `jwks` 对象。 | 对应私钥。 |
| RP JWKS URI | 注册提供公钥 JWKS 的 HTTPS `jwks_uri`。 | 对应私钥，并维护 HTTPS 端点。 |

验证只使用所选来源。RP 密钥查找或签名验证失败时，不会改用平台 client-auth 密钥。动态注册使用 `private_key_jwt` 时，必须提供 `jwks` 或 `jwks_uri` 中的一项。

动态注册的客户端可在 With 打开应用 OIDC 页面，再通过链接进入组织的 OIDC 客户端管理页面。组织 OWNER 可以在那里选择来源并保存公钥配置。如果编辑期间页面内容已变化，请重新加载当前配置，再保存。

## 创建 RP 公钥 JWKS

在受保护的后端工作目录中运行以下 Node.js 示例。它创建新的密钥对。如果 `rp-private.pem` 已存在，示例会失败，避免意外覆盖私钥。

```js
import { generateKeyPairSync } from 'node:crypto';
import { writeFileSync } from 'node:fs';

const { privateKey, publicKey } = generateKeyPairSync('rsa', {
  modulusLength: 2048,
});
writeFileSync('rp-private.pem', privateKey.export({
  format: 'pem',
  type: 'pkcs8',
}), { mode: 0o600, flag: 'wx' });
const jwk = publicKey.export({ format: 'jwk' });
const jwks = { keys: [{
  ...jwk,
  kid: 'rp-signing-1',
  alg: 'RS256',
  use: 'sig',
  key_ops: ['verify'],
}] };
writeFileSync('rp-public-jwks.json', JSON.stringify(jwks, null, 2), {
  flag: 'wx',
});
```

将 `rp-public-jwks.json` 的内容注册为内联 JWKS，或通过 HTTPS JWKS URI 提供。不要公开 `rp-private.pem`。

每把公钥必须是至少 2048 位的 RSA 密钥，使用 RS256。`d`、`p`、`q` 等 JWK 私钥字段会被拒绝。JWKS 最多包含 16 把密钥。为每把密钥设置不同的非空 `kid`，并在签名 JWT 的 header 中携带它。JWT 未提供 `kid` 时，密钥集合必须只有一把密钥。

## 签名客户端 assertion

使用所选来源对应的私钥签名 RS256 JWT。在 `/token` 表单中发送标准的 `client_assertion_type` 和 `client_assertion` 字段。

| Claim | 值 |
|---|---|
| `iss`、`sub` | 你的 `client_id`。 |
| `aud` | discovery 中完整且精确的 `token_endpoint` URL。不接受只有 issuer 的值。 |
| `iat` | 当前 epoch 时间，单位秒。保持后端时钟同步。 |
| `exp` | 大于 `iat`，且最多晚 300 秒。 |
| `jti` | 每次 assertion 使用全新的值，不得重用 assertion。 |

客户端 assertion 和 Request Object 是不同的 JWT。见[令牌兑换](/zh-cn/oidc/flow/#2-令牌交换)和[签名请求示例](/zh-cn/oidc/advanced/#签名-request-object)。

## 轮换 RP 密钥

计划轮换时，保持密钥来源类型不变：

1. 生成具有新 `kid` 的替换密钥。JWKS 中保留当前公钥，并加入新公钥。
2. 内联 JWKS 在 With 保存合并后的集合。使用 JWKS URI 时，先发布合并集合，再用新密钥签名。提供方缓存远程 RP 公钥最多 60 秒，并限制未知 `kid` 触发的刷新频率。
3. 用新私钥签名新的 assertion 和 Request Object，确认请求成功。
4. 旧密钥签名的请求完成或到期后，移除旧公钥，并保存内联集合或更新 HTTPS 文档。

常规轮换时不要同时更换密钥来源类型。更换来源或编辑密钥可能使正在进行的授权失效；此时重新发起授权。

怀疑私钥泄露时，及时移除对应公钥、更新后端签名，并检查受影响的客户端会话。远程缓存可能在剩余缓存期限内保留旧公钥。如果需要立即停止客户端，请使用[应用生命周期控制](/zh-cn/with-portal/application-lifecycle/)。

轮换 RP 密钥不会轮换提供方的 ID Token 密钥或应用的 access-token 签名密钥。

## 相关文档

- [动态注册 API](/zh-cn/oidc/dynamic-registration/)
- [OIDC 排错](/zh-cn/oidc/troubleshooting/)
- [管理应用 token-signing 密钥](/zh-cn/with-portal/organizations-and-applications/#管理令牌签名密钥)