Skip to content

JOSE 基礎: JWS、JWE、JWK、JWKS、kid

JOSE(JavaScript Object Signing and Encryption)は、JSON 形のトークンに対して署名・暗号化・鍵表現の方法を定める IETF 仕様群の総称です。OIDC 実装は JWS / JWE / JWK / JWKS の 4 つすべてを内部で扱います — 大抵は表に出ませんが、ときどき直接登場します。本ページは、id_tokenjwks_uri、JAR の request= パラメータ、kid を理解するために押さえておきたい最小限を扱います。

このページで触れる仕様

メンタルモデル

  • JWS が署名する。JWE が暗号化する。JWK は鍵 1 個。JWKS は鍵集合。kid はどの鍵かを選ぶ。
  • OIDC で目にする JWT はすべて JWS — header.payload.signature
  • ID トークン / userinfo / authorize 応答が暗号化されるとき、署名の上にかぶさる外側のエンベロープが JWE。
  • /jwks の JWKS のおかげで RP は ID トークンをオフラインで検証できる。OP は新しい鍵を先んじて追加してからローテーションする。

JWS — JSON Web Signature

JWS は JWT が使う署名スキームです。コンパクトシリアライズは、ドットでつないだ 3 つの base64url セグメントです。

<base64url(header)>.<base64url(payload)>.<base64url(signature)>

ヘッダは署名アルゴリズムと鍵を名付ける JSON オブジェクトです。

json
{ "alg": "ES256", "kid": "2026-q1" }

payload はトークンの claim(JSON オブジェクト)です。signature は header + "." + payload を覆い、alg で名付けたアルゴリズムと kid で名付けた鍵で計算されます。

OIDC では JWS は次の用途で使われます。

アーティファクト仕様署名者
id_tokenOIDC Core 1.0 §2OP の署名鍵。
アクセストークン(デフォルト JWT 経路)RFC 9068OP の署名鍵。
request / request_uri(JAR)RFC 9101RP の鍵。クライアントの jwks_uri で公開。
client_assertionprivate_key_jwtRFC 7523RP の鍵。
Authorize 応答(JARM)OpenID FAPI JARMOP の署名鍵。
logout_token(Back-Channel Logout)OIDC BCL 1.0OP の署名鍵。

受信側は、関連する JWKS の公開鍵に対してアルゴリズムを再実行して検証します。署名が一致し、claim(issaudexp)が期待と合えばトークンを受理します。

JWE — JSON Web Encryption

JWE は暗号化版です。コンパクトシリアライズは 5 セグメントです。

<base64url(header)>.<base64url(encrypted_key)>.<base64url(iv)>.<base64url(ciphertext)>.<base64url(tag)>

ヘッダは 2 つのアルゴリズム名を持ちます。

フィールド内容
alg鍵管理アルゴリズム。 メッセージごとのコンテンツ鍵を受信者にどう届けるか: RSA-OAEP-256(RSA 鍵搬送)、ECDH-ES(ダイレクト ECDH)、ECDH-ES+A128KW / ECDH-ES+A256KW(ECDH と AES 鍵ラップ)。
encコンテンツ暗号化アルゴリズム。 payload をどう暗号化するか: A128GCMA256GCM

OIDC では JWE は、組み込み側やクライアントが署名の上に機密性を重ねたいときに 外側のエンベロープ として使われます — RP の公開鍵で暗号化された id_token、暗号化された userinfo 応答、暗号化された introspection 応答、暗号化された authorize 応答(暗号化付き JARM)。内側のアーティファクトは依然として JWS で、JWE はそれを包んでいるだけです。

完全な設定(op.WithEncryptionKeysetop.WithSupportedEncryptionAlgs)は JWE 暗号化のユースケース を参照。

JWK — JSON Web Key

JWK は単一の暗号鍵を JSON で表す標準形式です。

json
{
  "kty": "EC",
  "crv": "P-256",
  "kid": "2026-q1",
  "use": "sig",
  "alg": "ES256",
  "x": "...",
  "y": "..."
}
フィールド内容
kty鍵種別: RSAEC(楕円曲線)、OKP(Edwards 曲線: Ed25519、Ed448)。
kid鍵 id — JWKS から鍵を選び出すラベル。
usesig(署名)または enc(暗号)。
algこの鍵が用いられるアルゴリズム — 呼び出し側が弱いものに差し替えられないよう pin される。

公開時の JWK には公開鍵だけが含まれ、対になる秘密鍵は OP に留まります。

JWKS — JWK Set

JWKS は JWK の JSON 配列です。

json
{
  "keys": [
    { "kty": "EC", "kid": "2026-q1", ... },
    { "kty": "EC", "kid": "2025-q4", ... }
  ]
}

OP は公開署名鍵を jwks_uri(discovery 文書で広告)に公開します。RP は JWKS を 1 度取得してキャッシュし、ID トークンの署名検証にオフラインで使います。鍵ローテーション中、OP は RP のキャッシュが収束するのに十分な期間、前の鍵を集合に残します — 運用: 鍵ローテーション を参照。

jwks_uri と JWS ヘッダの jwk の違い
  • jwks_uri(discovery のフィールド)は、OP が JWKS を serve する URL。安定でキャッシュ可能、RP は自身の都合で取得します。
  • jwk JWS ヘッダ は、トークンのヘッダに インラインで 埋め込まれた JWK。RFC 7515 は許容していますが、RFC 8725 §3.5 は「トークンが自分で名乗った鍵を信頼することは alg-confusion の典型的な落とし穴のひとつ」と警告しています — 誰でも JWS を作成し、自前の jwk をヘッダに付けて検証側に「これで検証して」と渡せるからです。本ライブラリは入力トークンのインライン jwk ヘッダの盲信は決して行いません — 出力アーティファクトの鍵は OP 自身の JWKS から、クライアント由来の JWS の検証鍵は設定されたクライアントの jwks_uri から取得します。

kid — どの鍵を使うかの指定

kid は鍵 id です。JWS が到着すると、検証側は次の手順を踏みます。

  1. JWS ヘッダから kid を読む。
  2. 関連する JWKS から、kid が一致する JWK を探す。
  3. alg で名付けたアルゴリズムを、その鍵に対して実行して署名を検証する。

kid がなければ、検証側は集合内のすべての鍵を順に試すことになります — 遅いだけでなく、攻撃者にどの鍵で混乱させるかを選ばせる足元の罠でもあります。本ライブラリは生成するすべての JWS に kid を必ず付け、関連する JWKS に kid が見つからない入力トークンを拒否します。

kid がアクティブセットには一致しないが、最近 retired した鍵に一致する入力トークンについては、op.AuditKeyRetiredKidPresented を発火します — 鍵ローテーションについて来られていない RP をダッシュボードが特定できるようにするためです。詳細は 運用: 鍵ローテーション を参照。

なぜ本ライブラリは alg allow-list を閉じているか

JOSE のアルゴリズムレジストリには 2 つの攻撃クラスが住んでおり、その典型的な防御は「該当アルゴリズムを検証側が到達する型の中で決して名指さない」ことです。

署名で拒否しているアルゴリズム

  • alg=none(RFC 7518 §3.6) — 「署名」が空文字列。RFC 8725 §3.1 は「実装は none ベースの JWT を信頼してはならない」と規定。本ライブラリはアルゴリズム enum に none を含めていません。
  • HS256 / HS384 / HS512(HMAC ファミリ) — 対称 MAC。alg-confusion 攻撃クラス(RFC 8725 §3.2)は「非対称と対称の両方を受け付ける検証側」が前提です — 攻撃者は alg=HS256 の JWS を作り、OP の 公開 鍵を HMAC のシークレットとして使い、ずさんな検証側はそれを通してしまいます。本ライブラリは enum にどの HMAC アルゴリズムも含めていません。

受け入れているアルゴリズム

用途アルゴリズム
OP 発行(ID トークン、JWT アクセストークン、JARM の出力署名)ES256 のみ。WithKeyset は P-256 でない署名鍵を op.New で拒否します。
検証(入力 JWS)RS256PS256ES256EdDSARS256 を検証側で受理しているのは、OIDC Core 1.0 §10.1 が ID トークン検証で MUST-implement と定めているためです。

この 4 つが internal/jose.Algorithm の閉じた enum です。型のゼロ値デフォルトはなく、より広いレジストリへのフォールバックもありません。depguard の lint ルールが、internal/jose/ の外で背後の JOSE パッケージを import することを禁じているので、将来のコード経路が noneHS* を不意に再導入することもありません。完全な背景は 設計判断 #11 を参照。

JWE allow-list

internal/jose/jweparam.go の JWE 許可集合も同様に閉じています。

フィールド許可拒否
alg(鍵管理)RSA-OAEP-256ECDH-ESECDH-ES+A128KWECDH-ES+A256KWRSA1_5(Bleichenbacher クラス)、dir(鍵ラップなし)、A*KW / A*GCMKW(対称 — HMAC と同じ鍵配布の問題)。
enc(コンテンツ暗号化)A128GCMA256GCMA*CBC-HS*(AES-CBC と HMAC — CBC-with-MAC 由来の歴史的落とし穴と、GCM より広い攻撃面)。

絞り込みは意図的です — 拒否されているアルゴリズムにはいずれも、OAuth / OIDC エコシステムが既に retire した(RSA1_5)か、プロファイルとして採用しなかった(OAuth bearer の CBC-with-MAC)攻撃クラスが文書化されています。組み込み側は op.WithSupportedEncryptionAlgs(algs, encs []string) でデプロイごとに広告集合をさらに絞り込めますが、本ライブラリの allow-list を超えて広げることはできません。

次に読む