Slide 1

Slide 1 text

JWTアクセストークンとIDトークンは 誰が何のために必要としているのか 産業⽀援グループ fannaly事業部 / fannaly auth エンジニア 宮部侑弥

Slide 2

Slide 2 text

⾃⼰紹介 宮部 侑弥 クラスメソッド株式会社 fannaly事業部 fannaly auth エンジニア 認証基盤の開発に従事 2

Slide 3

Slide 3 text

どっちがどのトークンの中⾝? A B ヘッダ ヘッダ { "alg": "RS256", "typ": "JWT" } { "alg": "RS256", "typ": "at+jwt" } ペイロード ペイロード { { "iss": "https://as.example.com", "sub": "5ba552d67", "aud": "s6BhdRkqt3", "exp": 1639528912, "iat": 1618354090, "jti": "9f8e7d6c5b4a", "nonce": "n-0S6_WzA2Mj" "iss": "https://as.example.com", "sub": "5ba552d67", "aud": "https://api.example.com", "client_id": "s6BhdRkqt3", "exp": 1639528912, "iat": 1618354090, "jti": "9f8e7d6c5b4a", "scope": "orders:read" } } ■ アクセストークンとIDトークンのJWTをデコードした際のヘッダとペイロード 3

Slide 4

Slide 4 text

仕様⾃⾝が「似ている」と⾔っている The JWT access token data layout described here is very similar to that of the id_token as defined by [OpenID.Core]. RFC 9068 Section 5 https://www.rfc-editor.org/rfc/rfc9068#section-5 アクセストークンが JWT なのは仕様の要求ではない OAuth 2.0 はアクセストークンの形式を何も決めていない。 ⼀般的なのはopaqueとJWT。 RFC 6749 Section 1.4 https://www.rfc-editor.org/rfc/rfc6749#section-1.4 4

Slide 5

Slide 5 text

JWTにする利点 有効? 誰の? どのスコープ? アクセストークン (opaque) クライアント リソースサーバー 認可サーバー イントロスペクション 有効期限‧スコープ アクセストークン (JWT) クライアント リソースサーバー 署名を検証して中を読む ✕ 認可サーバー 問い合わせが不要 (イントロスペクション) JWTにすることで認可サーバーを介す必要がなくなる RFC 9068 Section 1 https://www.rfc-editor.org/rfc/rfc9068#section-1 5

Slide 6

Slide 6 text

audが違う場合がある IDトークン アクセストークン ヘッダ ヘッダ { "alg": "RS256", "typ": "JWT" } { "alg": "RS256", "typ": "at+jwt" } ペイロード ペイロード { { "iss": "https://as.example.com", "sub": "5ba552d67", "aud": "s6BhdRkqt3", "exp": 1639528912, "iat": 1618354090, "nonce": "n-0S6_WzA2Mj" "iss": "https://as.example.com", "sub": "5ba552d67", "aud": "https://api.example.com", "client_id": "s6BhdRkqt3", "exp": 1639528912, "iat": 1618354090, "jti": "9f8e7d6c5b4a", "scope": "orders:read" } } IDトークンの aud → クライアントID アクセストークンの aud → リソースサーバーの識別⼦ 6

Slide 7

Slide 7 text

audが違うということは宛先が違う IDトークン 認可サーバー クライアント リソースサーバー アクセストークン ● IDトークン クライアントが受け取り、読むのもクライアント ● アクセストークン クライアントが受け取り、読むのはリソースサーバー 7

Slide 8

Slide 8 text

クライアントは読まずに送るだけ The client MUST NOT inspect the content of the access token RFC 9068 Section 6 https://www.rfc-editor.org/rfc/rfc9068#section-6 中⾝を⾒ずにリソースサーバーへ送る Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9.eyJpc3Mi… 個⼈情報が⼊っていることもあり読んでログや画⾯に出せば漏えいになる 中⾝を⾒て検証するのは受け取ったリソースサーバーの役割 8

Slide 9

Slide 9 text

トークンを受け取った側はどう⾒分ける? IDトークン 保護は緩いことが多い 認可サーバー JWKS リソースサーバー 公開されている署名鍵 署名検証 OK アクセストークン リソースサーバー 署名検証が通るだけで受け⼊れると、IDトークンも受け⼊れてしまう 認可サーバー id_token_hint にアクセストークンを⼊れられても同様 9

Slide 10

Slide 10 text

typ ヘッダで⾒分ける IDトークン { "alg": "RS256", "typ": "JWT" } アクセストークン { "alg": "RS256", "typ": "at+jwt" } The resource server MUST verify that the "typ" header value is "at+jwt" or "application/at+jwt" and reject tokens carrying any other value. RFC 9068 Section 4 https://www.rfc-editor.org/rfc/rfc9068#section-4 署名が通ったかどうかと、それが何のトークンなのかは、別の話 10

Slide 11

Slide 11 text

typ は絶対にあるのか RFC 9068 は 2021年10⽉発⾏。OAuth 2.0(RFC 6749, 2012年10⽉)から9年後にできた⽐較的新しい仕様 Microsoft Entra ID アクセストークンの typ は常に JWT Okta(カスタム認可サーバー) アクセストークンに typ が付かない Auth0 デフォルトは JWT。RFC 9068 プロファイルを選んだときだけ at+jwt IDトークン OpenID Connect Core は typ を定めていない(歴史的にJWTの場合が多い) 各社の公式ドキュメント(2026年10⽉時点)。URL は参考⽂献に記載 typ に頼れないときは、検証ルールを排他的にする If more than one kind of JWT can be issued by the same issuer, the validation rules for those JWTs MUST be written such that they are mutually exclusive, rejecting JWTs of the wrong kind. 例: aud が⾃分の識別⼦か、⽚⽅のトークンにしか存在しないクレームがあるか RFC 8725 Section 3.12 https://www.rfc-editor.org/rfc/rfc8725#section-3.12 11

Slide 12

Slide 12 text

⽚⽅にしか存在しないクレームとは Q. 認可のためのアクセストークンなら認証情報はないのでは? A. ないとは⾔い切れない auth_time OPTIONAL - as defined in Section 2 of [OpenID.Core]. acr OPTIONAL - as defined in Section 2 of [OpenID.Core]. amr OPTIONAL - as defined in Section 2 of [OpenID.Core]. RFC 9068 Section 2 https://www.rfc-editor.org/rfc/rfc9068#section-2 クレームで区別するための標準仕様はない IDトークンは OIDC Discovery で claims_supported が公開されている アクセストークンにはそれに相当する仕様がない 各サービスの公開資料等で⾒⽐べる OpenID Connect Discovery 1.0 https://openid.net/specs/openid-connect-discovery-1_0.html 12

Slide 13

Slide 13 text

まとめ IDトークン アクセストークン ヘッダ { "alg": "RS256", "typ": "JWT" } ヘッダ { "alg": "RS256", "typ": "at+jwt" } ペイロード { "iss": "https://as.example.com", "sub": "5ba552d67", "aud": "s6BhdRkqt3", "exp": 1639528912, "iat": 1618354090, "nonce": "n-0S6_WzA2Mj" } ペイロード { "iss": "https://as.example.com", "sub": "5ba552d67", "aud": "https://api.example.com", "client_id": "s6BhdRkqt3", "exp": 1639528912, "iat": 1618354090, "jti": "9f8e7d6c5b4a", "scope": "orders:read" } 似た⾒た⽬の JWT でも宛先が違う クライアントは読まずに渡すし受け取った側は typ、無ければ aud や⽚⽅にしかないクレームで判別できる 13

Slide 14

Slide 14 text

参考⽂献 RFC 9068 JWT Profile for OAuth 2.0 Access Tokens Microsoft Entra ID Access token claims reference https://www.rfc-editor.org/rfc/rfc9068 https://learn.microsoft.com/en-us/entra/identity-platform/access-token-clai ms-reference RFC 6749 The OAuth 2.0 Authorization Framework https://www.rfc-editor.org/rfc/rfc6749 Okta The typ field is missing from the access token header RFC 7662 OAuth 2.0 Token Introspection https://support.okta.com/help/s/article/the-typ-field-is-missing-from-the-ac cess-token-header https://www.rfc-editor.org/rfc/rfc7662 RFC 8725 JSON Web Token Best Current Practices https://www.rfc-editor.org/rfc/rfc8725 Auth0 Access Token Profiles https://auth0.com/docs/secure/tokens/access-tokens/access-token-profiles OpenID Connect Core 1.0 https://openid.net/specs/openid-connect-core-1_0.html OpenID Connect Discovery 1.0 https://openid.net/specs/openid-connect-discovery-1_0.html 14

Slide 15

Slide 15 text

15