Edited at

OAuth 2.0 クライアント認証


はじめに

この記事では、OAuth 2.0 の『クライアント認証』について説明します。

RFC 6749 に記述されているクライアント認証方式のほか、クライアントアサーションやクライアント証明書を用いるクライアント認証方式についても説明します。


1. クライアント認証方式


1.1. トークンエンドポイント

認可サーバーがあります。

client_auth_authorization_server.png

認可サーバーからアクセストークンの発行を受けたいクライアントアプリケーションがあります。

client_auth_client.png

アクセストークンは、幾つかの例外を除き、認可サーバーのトークンエンドポイントから発行されます。そのため、認可サーバーはトークンエンドポイントを用意します。

client_auth_token_endpoint.png

クライアントアプリケーションは、アクセストークンの発行を受けるために、トークンエンドポイントにトークンリクエストを投げます。

client_auth_token_request.png

認可サーバーは、トークンレスポンスを返します。この応答の中に、アクセストークンが含まれます。

client_auth_token_response.png


1.2. クライアントタイプ

クライアントアプリケーションには、クライアントタイプRFC 6749, 2.1. Client Types)という属性があります。

client_auth_client_type.png

この属性の値は、public(パブリック)もしくは confidential(コンフィデンシャル)のどちらかです。

client_auth_client_types.png

クライアントタイプが confidential の場合、

client_auth_confidential.png

トークンエンドポイントにアクセスする際、

client_auth_at_token_endpoint.png

クライアント認証という手続きが必要になります。これは、クライアントの身元を確認するための処理です。

client_auth_if_confidential.png


1.3. client_secret_post

昔ながらのクライアント認証の方法では、まず、当該クライアントアプリケーション用のクライアント IDクライアントシークレットを認可サーバーが生成し、あらかじめクライアントアプリケーションに渡しておきます。

client_auth_client_id_and_secret.png

クライアントアプリケーションは、トークンリクエストを投げる際、

client_auth_token_request_2.png

トークンリクエストにクライアント ID とクライアントシークレットを含めます。認可サーバーは、トークンリクエストに含まれるクライアント ID とクライアントシークレットをチェックすることで、クライアントの身元を確認することができます。

client_auth_token_request_with_client_id_and_secret.png

トークンリクエストにクライアント ID とクライアントシークレットを含める方法で一番分かりやすい方法は、client_id および client_secret というリクエストパラメーターを使う方法です。

client_auth_client_secret_post.png

このクライアント認証方式には client_secret_post という名前が与えられています(OIDC Core, 9. Client Authentication)。


1.4. client_secret_basic

トークンリクエストにクライアント ID とクライアントシークレットを含めるもう一つの方法は、ベーシック認証(RFC 7617)を使う方法です。

この方法を使う場合、まず、クライアント ID、コロン、クライアントシークレットを連結し、一つの文字列を作ります。

client_auth_client_secret_basic_raw_string.png

次に、この文字列を BASE64(RFC 4648)でエンコードします。

client_auth_client_secret_basic_base64.png

そして、出来上がった BASE64 文字列を、トークンリクエストの Authorization ヘッダーに埋め込みます。

client_auth_client_secret_basic_token_request.png

このクライアント認証方式には client_secret_basic という名前が与えられています(OIDC Core, 9. Client Authentication)。

client_secret_postclient_secret_basic は、RFC 6749, 2.3.1. Client Password に書かれているクライアント認証方式です。


1.5. client_secret_jwt

クライアントシークレットを直接トークンリクエストに含めずとも、クライアントシークレットを持っていることを間接的に証明する方法があります。

まず、何らかのデータを用意します。

client_auth_client_secret_jwt_data.png

次に、クライアントシークレットを用いてそのデータに対する署名を生成します。

client_auth_client_secret_jwt_signature.png

そして、そのデータと署名を、トークンリクエストに含めます。

client_auth_client_secret_jwt_token_request.png

認可サーバーは、その署名を検証することで、トークンリクエストを投げてきたクライアントアプリケーションがクライアントシークレットを持っていることを確認でき、もってクライアント認証とすることができます。

client_auth_client_secret_jwt_verification.png

ここで用意するデータの形式にはルールがあります。詳細は RFC 7523, 2.2. Using JWTs for Client Authentication に書かれています。簡単に言うと、iss クレームなどを含む JSON です。

client_auth_client_secret_jwt_payload.png

この JSON に対する署名は、RFC 7515(JSON Web Signature)に定義されている方法でおこないます。署名の結果、JWT(RFC 7519)が生成されますが、この JWT は、クライアント認証の文脈ではクライアントアサーションと呼ばれます。

そして、このクライアントアサーションを client_assertion リクエストパラメーターの値としてトークンリクエストに含めます。また、同時に、client_assertion_type リクエストパラメーターも追加します。client_assertion_type の値は、urn:ietf:params:oauth:client-assertion-type:jwt-bearer という固定値です。

client_auth_client_secret_jwt_client_assertion.png

このクライアント認証方式には client_secret_jwt という名前が与えられています(OIDC Core, 9. Client Authentication)。


1.6. private_key_jwt

前節のクライアント認証方式では、クライアントアサーションの署名を生成する際、クライアントシークレットという共有鍵を用いました。一方、クライアントアサーションの署名と検証に非対称鍵を用いる方法もあります。

まず、クライアント側で、秘密鍵と公開鍵の組を生成します。

client_auth_private_key_jwt_key_pair.png

そして、何らかの方法で、認可サーバーが公開鍵を参照できるようにしておきます。

client_auth_private_key_jwt_public_key.png

トークンリクエストに先立って、クライアントは、RFC 7523, 2.2. Using JWTs for Client Authentication の仕様に従って JSON データを用意します。

client_auth_private_key_jwt_payload.png

そのデータに対して、秘密鍵を用いて署名をおこないます。

client_auth_private_key_jwt_signature.png

生成されたクライアントアサーションを client_assertion リクエストパラメーターの値とし、トークンリクエストをおこないます。

client_auth_private_key_jwt_token_request.png

認可サーバーは、トークンリクエストの中からクライアントアサーションを取り出します。

client_auth_private_key_jwt_extraction.png

そして、公開鍵を用いてクライアントアサーションの署名検証をおこないます。

client_auth_private_key_jwt_verification.png

このクライアント認証方式には private_key_jwt という名前が与えられています(OIDC Core, 9. Client Authentication)。


1.7. tls_client_auth

OAuth 2.0 Mutual TLS Client Authentication and Certificate-Bound Access Tokens(以降 MTLS)という仕様があります。この仕様の「2. Mutual TLS for OAuth Client Authentication」には、クライアント証明書を用いるクライアント認証方式が定義されています。

MTLS で定義されているクライアント認証方式を用いるためには、まず、クライアントアプリケーションとトークンエンドポイントの間の接続が、Mutual TLS でなければなりません。

client_auth_tls_client_auth_mutual_tls.png

通常の TLS では、サーバー側のみ証明書の提示をおこないますが、Mutual TLS では、クライアント側も自身の証明書を提示します。この結果、サーバー側にクライアント証明書が渡ってきます。

client_auth_tls_client_auth_pass.png

サーバーは、そのクライアント証明書をクライアント認証に用います。

client_auth_tls_client_auth_client_auth.png

クライアント証明書として PKI 証明書を用いる場合、クライアントは、その証明書の主体を識別するための情報を事前にサーバーに登録しておかなければなりません。主体を識別する情報は、次のいずれかです。

識別情報
クライアントメタデータ名

Subject Distinguished Name
tls_client_auth_subject_dn

Subject Alternative Name, DNS
tls_client_auth_san_dns

Subject Alternative Name, URI
tls_client_auth_san_uri

Subject Alternative Name, IP address
tls_client_auth_san_ip

Subject Alternative Name, Email
tls_client_auth_san_email

サーバーは、受け取ったクライアント証明書の主体識別情報が事前登録されているものと一致することを確認し、もってクライアント認証とします。

このクライアント認証方式には tls_client_auth という名前が与えられています(MTLS, 2.1.1. PKI Method Metadata Value)。

なお、クライアント証明書には OAuth 2.0 の文脈におけるクライアント ID は入っていないので、クライアント証明書だけではクライアントを特定することはできません。そのため、クライアント証明書を用いるクライアント認証をおこなう際は、別途クライアント ID をリクエストに含める必要があります。通常は client_id リクエストパラメーターが使用されます。


1.8. self_signed_tls_client_auth

クライアント証明書を用いるクライアント認証において、PKI 証明書ではなく、自己署名証明書を用いる場合もあります。自己署名証明書を用いる場合、クライアントは、証明書を事前にサーバーに登録しておかなければなりません。

このクライアント認証方式には self_signed_tls_client_auth という名前が与えられています(MTLS, 2.2.1. Self-Signed Method Metadata Value)。


2. メタデータ

クライアント認証方式に関連するメタデータを紹介します。


2.1. サーバーメタデータ


2.1.1. token_endpoint_auth_methods_supported

トークンエンドポイントでサポートするクライアント認証方式です。client_secret_basicprivate_key_jwt などの値を持つ配列です。


2.1.2. token_endpoint_auth_signing_alg_values_supported

トークンエンドポイントにおいてクライアントアサーションによるクライアント認証をおこなう際、クライアントアサーションの署名で使用可能なアルゴリズムです。HS256ES256 など、RFC 7518(JSON Web Algorithms)の 3.1. "alg" (Algorithm) Header Parameter Values for JWS に列挙されている値を持つ配列です。

jws_algs.png


2.1.3. revocation_endpoint_auth_methods_supported

リボケーションエンドポイント(RFC 7009)でサポートするクライアント認証方式です。内容は token_endpoint_auth_methods_supported と同じです。


2.1.4 revocation_endpoint_auth_signing_alg_values_supported

リボケーションエンドポイント(RFC 7009)においてクライアントアサーションによるクライアント認証をおこなう際、クライアントアサーションの署名で使用可能なアルゴリズムです。内容は token_endpoint_auth_signing_alg_values_supported と同じです。


2.1.5. introspection_endpoint_auth_methods_supported

イントロスペクションエンドポイント(RFC 7662)でサポートするクライアント認証方式です。内容は token_endpoint_auth_methods_supported と同じです。


2.1.6. introspection_endpoint_auth_signing_alg_values_supported

イントロスペクションエンドポイント(RFC 7662)においてクライアントアサーションによるクライアント認証をおこなう際、クライアントアサーションの署名で使用可能なアルゴリズムです。内容は token_endpoint_auth_signing_alg_values_supported と同じです。


2.1.7. バックチャネル認証エンドポイント関連

CIBA Core で定義されるバックチャネル認証エンドポイントは、仕様上、confidential クライアントしか利用できないことになっており、利用する際には必ずクライアント認証が必要となります。

ciba-ping-mode.png

参考:CIBA PING モードによるアクセストークン発行フロー

認可サーバーのメタデータを列挙している RFC 8141 では、トークンエンドポイント、リボケーションエンドポイント、イントロスペクションエンドポイント毎にそれぞれ、サポートするクライアント認証方式(*_endpoint_auth_methods_supported)とサポートするクライアントアサーション署名アルゴリズム(*_endpoint_auth_signing_alg_values_supported)を表すメタデータが用意されています。そのため、CIBA Core 仕様策定中、バックチャネル認証エンドポイント用にもメタデータを新しく定義してはどうかと提案しました(【Issue 102】CIBA: Metadata for client auth at backchannel endpoint)。

しかしながら、最終的には、バックチャネル認証エンドポイント用に新しくメタデータを定義はせず、トークンエンドポイント用のメタデータで代用することとなりました。そもそも論として、エンドポイント毎にクライアント認証関連のメタデータを定義してきたこれまでの慣習が良くない、という話になりました。この議論については、「世界最先端の認証認可技術、実装者による『CIBA』解説」の「3.2. クライアント認証」をご参照ください。


2.1.8. デバイス認可エンドポイント関連

もうすぐ RFC になる予定の OAuth 2.0 Device Authorization Grant、いわゆるデバイスフローでは、新たにデバイス認可エンドポイントが定義されます。クライアントが confidential クライアントの場合、他のエンドポイントと同様、デバイス認可エンドポイントにアクセスする際にクライアント認証が要求されます。

device_flow_with_Authlete.png

参考:デバイスフローと Authlete API

ただし、仕様書には、デバイス認可エンドポイントがサポートするクライアント認証方式を表すメタデータについて言及がありません。そこで、「デバイス認可エンドポイントにおけるクライアント認証方式に関する記述を仕様書に追加する予定があるか」という問いを OAuth メーリングリストに投げてみました([OAUTH-WG] Client Authentication Method at Device Authorization Endpoint)。

しかしながら、今までのところ、メタデータの扱いに関する議論に進捗はありません。デバイスフローについては公式テストも存在しないので、デバイス認可エンドポイントのクライアント認証方式の厳密な動作について気にする人もそれほどいないのでしょう。やむなく Authlete の実装では、CIBA に倣い、トークンエンドポイントのメタデータで代用することにしています。


2.2. クライアントメタデータ


2.2.1. token_endpoint_auth_method

クライアントがトークンエンドポイントで使用するクライアント認証方式です。client_secret_basicprivate_key_jwt などを指定します。クライアントタイプが public の場合はクライアント認証をおこなわないので、none を指定します。


2.2.2. token_endpoint_auth_signing_alg

クライアントがトークエンドポイントでクライアントアサーションを用いたクライアント認証をおこなう際、クライアントアサーションの署名に使うアルゴリズムです。RFC 7518(JSON Web Algorithms)の 3.1. "alg" (Algorithm) Header Parameter Values for JWS に列挙されている値のいずれかを指定します。

クライアント認証方式に client_secret_jwt を選んでいる場合は、署名アルゴリズムは対称鍵系である HS256HS384HS512 のいずれかになります。ただし、認可サーバーにより発行されたクライアントシークレットのエントロピーよりも高いビット数のアルゴリズムを選んでも、あまり益はないので注意してください。

一方、クライアント認証方式に private_key_jwt を選んでいる場合は、署名アルゴリズムに ES256 などの非対称鍵系アルゴリズムを設定することになります。


3. Financial-grade API による要求事項


3.1. クライアント認証方式

従来の OAuth 2.0 や OpenID Connect よりも高いセキュリティーを要求する Financial-grade APIFAPI)では、使用可能なクライアント認証方式に制限をかけています。

RFC 6749 に記述されている昔ながらのクライアント認証方式(client_secret_basicclient_secret_post)は、使用してはいけないことになっています。

Read-Only API 用のセキュリティープロファイルである FAPI Part 1 では、使用可能はクライアント認証方式は次の 4 つです。


  1. client_secret_jwt

  2. private_key_jwt

  3. tls_client_auth

  4. self_signed_tls_client_auth

Read-and-Write API 用のセキュリティープロファイルである FAPI Part 2 では、client_secret_jwt が使用不可となり、次の 3 つのクライアント認証方式のみが許されます。


  1. private_key_jwt

  2. tls_client_auth

  3. self_signed_tls_client_auth

まとめると、次表のとおりです。

client_auth_fapi.png


3.2. クライアントアサーション署名アルゴリズム

FAPI Part 2 の「8.6. JWS algorithm considerations」では、JWS の署名アルゴリズムに制限をかけています。Read-and-Write API の文脈では、ES256PS256 以外のアルゴリズムを使用してはいけないことになっています。

ps256_and_es256.png

この要求事項は、クライアントアサーションを用いるクライアント認証方式に影響を与えます。


3.3. キーサイズ

FAPI Part 1 の「5.2.2. Authorization Server」の 5 番目の規定により、クライアント認証で RSA 系アルゴリズムが用いられる場合、鍵のサイズは 2048 ビット以上でなければなりません。また、6 番目の規定により、楕円曲線系のアルゴリズムが用いられる場合、鍵のサイズは 160 ビット以上でなければなりません。


4. Authlete

Authlete(オースリート)は、

:white_check_mark: この記事で紹介したクライアント認証方式を全てサポートしています。

authlete_token_endpoint_auth_method.png

:white_check_mark: クライアントアサーション署名アルゴリズムも全てサポートしています。

authlete_token_endpoint_auth_signing_alg.png

:white_check_mark: クライアント証明書系(MTLS)とクライアントアサーション系(Private Key)の双方のカテゴリーで公式 FAPI 認証を取得している、(サンドボックスではなく)商用環境で利用可能な、世界で唯一の実装です(2019 年 7 月 14 日現在)。

certified_fapi_ops_20190714.png


さいごに

いろいろなサービスが API として提供されるようになり、便利な世の中になってきました。しかし、その一方で、不適切な実装のせいで、セキュリティー問題も頻発するようになってしまいました。

API 公開にあたってセキュリティーを重視されたい場合は、Financial-grade API の実装として公式認証を取得している Authlete の利用をご検討ください。お問い合わせは、Authlete 社のお問合せページ、または sales@authlete.com までご連絡ください。よろしくお願い致します。