Ory Hydra: Dynamic Client Registration
本文基於 Ory Hydra v25.4.0 分析其 Dynamic Client Registration(DCR)實作,包含 API 端點、支援欄位、安全機制與實際測試結果。
啟用 DCR
Section titled “啟用 DCR”Hydra 的 DCR 預設停用,需要在設定檔中明確啟用:
oidc: dynamic_client_registration: enabled: true default_scope: - openid - offline - offline_access啟用後,DCR 端點會在 Public API port 上生效。
API 端點
Section titled “API 端點”Hydra 提供兩套 Client 管理 API,DCR 屬於 Public API:
Public API(DCR)
Section titled “Public API(DCR)”| 方法 | 路徑 | 說明 |
|---|---|---|
POST | /oauth2/register | 註冊新的 Client |
GET | /oauth2/register/{id} | 取得 Client 資訊 |
PUT | /oauth2/register/{id} | 更新 Client(完整替換) |
DELETE | /oauth2/register/{id} | 刪除 Client |
Admin API
Section titled “Admin API”| 方法 | 路徑 | 說明 |
|---|---|---|
POST | /admin/clients | 建立 Client(可自訂 client_id) |
GET | /admin/clients | 列出所有 Client |
GET | /admin/clients/{id} | 取得 Client |
PUT | /admin/clients/{id} | 更新 Client |
PATCH | /admin/clients/{id} | 部分更新 Client |
DELETE | /admin/clients/{id} | 刪除 Client |
DCR 端點是 Admin API 的子集,主要差異:
- 不能自訂
client_id(強制使用 UUID4) - 不能自訂
client_secret(由伺服器產生) - 不能設定
metadata、access_token_strategy、skip_consent等管理欄位 - 沒有
PATCH方法和 Token lifespan 設定
以下使用 Docker 啟動 Hydra v25.4.0 進行測試。
註冊 Client
Section titled “註冊 Client”POST /oauth2/register HTTP/1.1Host: localhost:4444Content-Type: application/json
{ "client_name": "Test Application", "redirect_uris": ["http://localhost:3000/callback"], "grant_types": ["authorization_code"], "response_types": ["code"], "scope": "openid offline", "token_endpoint_auth_method": "client_secret_basic"}回應:
{ "client_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "client_name": "Test Application", "client_secret": "generated-secret-value", "client_secret_expires_at": 0, "redirect_uris": ["http://localhost:3000/callback"], "grant_types": ["authorization_code"], "response_types": ["code"], "scope": "openid offline", "token_endpoint_auth_method": "client_secret_basic", "registration_access_token": "ory_at_...", "registration_client_uri": "http://localhost:4444/oauth2/register/a1b2c3d4-e5f6-7890-abcd-ef1234567890", "created_at": "2026-03-18T00:00:00Z", "updated_at": "2026-03-18T00:00:00Z"}重點觀察:
client_id為伺服器產生的 UUID4,無法自訂client_secret_expires_at永遠為0(不支援 secret 過期)- 回應包含
registration_access_token和registration_client_uri,用於後續管理操作
使用 Registration Access Token 查詢 Client
Section titled “使用 Registration Access Token 查詢 Client”GET /oauth2/register/a1b2c3d4-e5f6-7890-abcd-ef1234567890 HTTP/1.1Host: localhost:4444Authorization: Bearer ory_at_...registration_access_token 是存取 GET、PUT、DELETE 端點的唯一憑證。
更新 Client
Section titled “更新 Client”PUT /oauth2/register/a1b2c3d4-e5f6-7890-abcd-ef1234567890 HTTP/1.1Host: localhost:4444Authorization: Bearer ory_at_...Content-Type: application/json
{ "client_name": "Updated Application", "redirect_uris": ["http://localhost:3000/callback", "http://localhost:3000/callback2"], "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "scope": "openid offline", "token_endpoint_auth_method": "client_secret_basic"}重點觀察:
PUT是完整替換,未帶的欄位會被重設為預設值- 更新後會重新產生
registration_access_token(Token Rotation),舊的 Token 立即失效
未啟用 DCR 時的行為
Section titled “未啟用 DCR 時的行為”若未設定 oidc.dynamic_client_registration.enabled: true,所有 DCR 端點會回傳 404。
支援的 Client Metadata
Section titled “支援的 Client Metadata”標準 OAuth 2.0 / OIDC 欄位
Section titled “標準 OAuth 2.0 / OIDC 欄位”| 欄位 | 說明 |
|---|---|
client_name | Client 名稱 |
redirect_uris | Redirect URI 陣列 |
grant_types | 授權類型 |
response_types | 回應類型 |
scope | 授權範圍(空格分隔) |
token_endpoint_auth_method | Token Endpoint 認證方式 |
contacts | 聯絡人 email 陣列 |
client_uri | Client 資訊頁面 URL |
logo_uri | Logo URL |
policy_uri | 隱私權政策 URL |
tos_uri | 服務條款 URL |
audience | 允許的 Audience 清單 |
OpenID Connect 特定欄位
Section titled “OpenID Connect 特定欄位”| 欄位 | 說明 |
|---|---|
subject_type | public 或 pairwise |
sector_identifier_uri | Pairwise 計算用的 sector URI |
jwks_uri | JWK Set URL |
jwks | JWK Set(直接傳值) |
userinfo_signed_response_alg | 僅支援 none 或 RS256 |
frontchannel_logout_uri | Front-Channel Logout URI |
backchannel_logout_uri | Back-Channel Logout URI |
post_logout_redirect_uris | 登出後重導向 URI |
支援的認證方式(token_endpoint_auth_method)
Section titled “支援的認證方式(token_endpoint_auth_method)”| 值 | 說明 |
|---|---|
client_secret_basic | HTTP Basic Authentication |
client_secret_post | Secret 放在 POST body |
private_key_jwt | 使用私鑰簽署 JWT |
none | 不需認證(Public Client) |
支援的 Grant Types
Section titled “支援的 Grant Types”| 值 | 說明 |
|---|---|
authorization_code | Authorization Code Flow |
client_credentials | Client Credentials Flow |
implicit | Implicit Flow(不建議) |
refresh_token | Refresh Token |
urn:ietf:params:oauth:grant-type:jwt-bearer | JWT Assertion |
urn:ietf:params:oauth:grant-type:device_code | Device Code Flow |
註冊端點(POST)
Section titled “註冊端點(POST)”註冊端點不需要認證,任何人都可以註冊 Client。這符合 RFC 7591 的開放註冊模式。
如果需要保護註冊端點,Hydra 不提供內建的 Initial Access Token 機制,官方建議使用外部方案:
- 反向代理(如 Ory Oathkeeper)攔截請求
- mTLS 認證
- 網路層限制
管理端點(GET、PUT、DELETE)
Section titled “管理端點(GET、PUT、DELETE)”使用 registration_access_token 做 Bearer Token 驗證:
- Token 在註冊時產生,
PUT更新時會 rotate(舊 Token 失效,產生新 Token) - Token 不會過期
- Token 以 HMAC 簽章方式驗證,簽章儲存在資料庫中
RFC 合規分析
Section titled “RFC 合規分析”RFC 7591(Dynamic Client Registration Protocol)
Section titled “RFC 7591(Dynamic Client Registration Protocol)”| 要求 | Hydra 狀態 |
|---|---|
POST 註冊端點 | ✅ /oauth2/register |
回傳 client_id | ✅ 伺服器產生 UUID4 |
回傳 client_secret(Confidential Client) | ✅ |
回傳 registration_access_token | ✅ |
回傳 registration_client_uri | ✅ |
software_statement 支援 | ❌ 不支援 |
client_secret_expires_at | ⚠️ 永遠為 0(不支援過期) |
RFC 7592(Dynamic Client Registration Management Protocol)
Section titled “RFC 7592(Dynamic Client Registration Management Protocol)”| 要求 | Hydra 狀態 |
|---|---|
GET 讀取 Client 配置 | ✅ |
PUT 更新 Client 配置 | ✅ |
DELETE 刪除 Client | ✅ |
| Bearer Token 驗證 | ✅ registration_access_token |
| Token Rotation | ✅ PUT 時重新產生 Token |