ユースケース — Grant management
grant は、あるユーザがあるクライアントに何を同意したかを OP が記録したものです。scope と、RAR を使う場合は authorization_details が入ります。通常、OP はユーザとクライアントの組ごとに grant を 1 つだけ持ち、新しい認可のたびにそれを黙って更新するため、クライアントが grant に名前を付けることはありません。継続的な支払いマンデートや常設のデータアクセス同意のように grant が長く続く場合は、クライアントが grant を名指しして、後から内容を追加し、いまの内容を読み戻し、不要になったら失効させる必要があります。OAuth 2.0 Grant Management draft は、各 grant に安定した grant_id と、それに対する 5 つのアクションを定めています。
op.WithGrantManagement は grant_management_action / grant_id の認可パラメータを処理し、grant management エンドポイント(照会 / 失効)をマウントし、token レスポンスに grant_id を刻み、discovery で feature を公開します。
初回の認可のあとも、クライアントが同意にあたる grant を管理する必要がある場合に使います。特に、grant が後から増えうる場合や、ブラウザのセッションとは独立して失効させたい場合に向いています。短命なサインインのためには不要です。クライアントが grant を名指しする必要がなければ、認可コード、リフレッシュトークンのローテーション、通常のトークン失効のほうが単純です。
replace で authorization_details の要素を外すと、その要素は opaque アクセストークンとリフレッシュトークンのチェーンから取り除かれます。発行済みの JWT は、有効期限まで claim をそのまま持ちます。下段の箱に届くのは revoke だけです。create / replace / merge は grant が保持する内容を書き換え、query はそれを読み戻します。revoke は grant レコードを削除したうえで、そこにぶら下がるトークンを失効させます。
Experimental — IETF draft を追跡
Grant Management は公開済みの RFC ではなく IETF draft です。op.GrantManagementAction enum と op.WithGrantManagement は godoc で Experimental: と明記されており、draft 更新によって通信仕様に互換性のない変更が入り得ます。
5 つのアクション
create— 新規 grant を開始する。grant_idを伴ってはなりません。OP が採番して返します。同じユーザとクライアントでも、createのたびに別の grant ができます。replace— 参照先の grant の scope とauthorization_detailsを、新しいリクエストの内容で上書きする。grant_idが必須です。merge— 参照先の grant の scope とauthorization_detailsを、新しいリクエストの内容と和集合する。grant_idが必須です。query— grant を読む。GET {grant_management_endpoint}/{grant_id}。revoke— grant を削除する。DELETE {grant_management_endpoint}/{grant_id}。
create / replace / merge は認可リクエストに乗ります。query / revoke は grant management エンドポイントへの操作です。
設定
import "github.com/libraz/go-oidc-provider/op"
op.New(
/* 必須オプション */
op.WithGrantManagement(op.GrantManagement{
Actions: []op.GrantManagementAction{
op.GrantActionCreate, op.GrantActionReplace, op.GrantActionMerge,
op.GrantActionQuery, op.GrantActionRevoke,
},
ActionRequired: false,
}),
)Actions は OP が受理するアクションの 閉じた集合 です。grant_management_actions_supported として公開され、エンドポイントはこの集合の外の操作を拒否します。ActionRequired が true のとき grant_management_action を欠いた認可リクエストは拒否されます(discovery が grant_management_action_required: true を公開)。アクションは最低 1 つ必要で、それぞれ 5 つの値のいずれかである必要があります。重複や未知のアクションは op.New で拒否され、WithGrantManagement を 2 度呼んだ場合も同様です。
discovery 文書はこう公開します:
{
"grant_management_endpoint": "https://op.example.com/oidc/grant_management",
"grant_management_actions_supported": ["create", "replace", "merge", "query", "revoke"]
}エンドポイントのパスは既定でマウント prefix 配下の /grant_management です。op.WithEndpoints(op.Endpoints{GrantManagement: "..."}) で上書きできます。
grant の作成と拡張
クライアントは認可リクエストで grant_management_action(replace / merge では grant_id も)を渡します:
# create — grant_id は不可
curl -G --data-urlencode 'grant_management_action=create' \
--data-urlencode 'response_type=code' \
--data-urlencode 'client_id=demo' \
--data-urlencode 'redirect_uri=https://rp.example.com/callback' \
--data-urlencode 'scope=openid profile' \
https://op.example.com/oidc/auth同じパラメータは PAR の push でも検証されます。create、replace、merge のリクエストは、必ず明示的な同意画面を通ります。ファーストパーティ向けの同意の省略も、キャッシュ済みの grant による省略も適用されません。認可コードを交換すると、token レスポンスに grant の id が入ります。
{
"access_token": "...",
"token_type": "Bearer",
"grant_id": "g-9f3c..."
}後でその grant を変更するには、クライアントは受け取った grant_id を添えて、grant_management_action=replace(scope / authorization_details を上書き)または merge(和集合)で再認可します。ログイン中のユーザとこのクライアントのものではない grant_id は、invalid_grant で拒否されます。
| アクション | grant_id | scope / authorization_details への影響 |
|---|---|---|
create | 不可 | 新しいリクエストの内容に設定する |
replace | 必須 | 新しいリクエストの内容で上書きする |
merge | 必須 | 既存と新しいリクエストを和集合する |
grant の照会
grant id を末尾に付けてエンドポイントを GET し、所有者のクライアントとして認証します。このエンドポイントを呼べるのは confidential クライアントだけで、public クライアントは 401 invalid_client になります。URL パスに含まれる grant_id は秘密ではなく、プロキシのログやブラウザの履歴に残るためです。OP は所有者を確認するので、クライアントが他のクライアントの grant を読むことはできません。応答には、grant の現在の scope と authorization_details が入ります。
curl -u demo:demo-secret https://op.example.com/oidc/grant_management/g-9f3c...{
"scopes": [{"scope": "openid profile"}],
"authorization_details": [{"type": "payment_initiation", "actions": ["initiate"]}]
}grant にその項目の内容がなければ、メンバーごと省かれます。
grant の失効
DELETE が対象にするのは、指定された grant_id と、それに紐付くものだけです。具体的には、grant の JWT アクセストークン(失効方式に応じて tombstone かレジストリで失効)、opaque アクセストークン、リフレッシュトークン、そして最後に grant レコードです。そのため、後続の照会では「存在しない」と応答します。同じ subject とクライアントが持つ別の grant には影響しません。subject やクライアントのすべての grant を失効させたい場合は、grant ID を列挙して自分で削除してください。
| 結果 | 応答 |
|---|---|
| 失効に成功 | 204 No Content。その grant の grant_management.revoked 監査イベントを記録。別のリクエストが先に削除していた場合も 204 |
| grant が存在しない、または別のクライアントのもの | 404 invalid_request。連鎖失効は試みない |
| grant ストアが存在の有無を判断できない | 500 server_error。連鎖失効は行わない。再試行する |
| 連鎖失効の途中で失敗 | 500 server_error と grant_management.revoke_failed の監査イベント。grant レコードは残るので、照会も再実行もできる |
| public クライアント | 401 invalid_client |
curl -u demo:demo-secret -X DELETE https://op.example.com/oidc/grant_management/g-9f3c...公開済みの grant_management_actions_supported 集合にない操作に対しては、エンドポイントは 405 Method Not Allowed を返し、Allow ヘッダには有効な操作だけを並べます。そのため query だけを登録したクライアントには DELETE は受理されません。
続きはこちら
- Rich authorization requests — grant が保持し
mergeが和集合するauthorization_details。 - リフレッシュトークン — 失効カスケードが撤去するもの。
- 監査イベント —
grant_management.revokedイベントの形。