Table of Contents
RFC 7636: Proof Key for Code Exchange (PKCE, 「ピクシー」と発音します) は、 認可コード横取り攻撃(authorization code interception attack) への対策に関する仕様です。
2015 年 9 月に出版された同仕様は、認可コードフローの各種リクエストに関し、いくつかの追加パラメーターを定義しています。
code_challenge
パラメーターと code_challenge_method
パラメーターを追加code_verifier
パラメーターを追加この仕様により認可サーバーは、悪意のある(正当なコードベリファイアを持たない)クライアントアプリからのトークンリクエストを拒否できるようになります。
PKCE に対応したクライアントアプリは、認可リクエストに code_challenge
パラメーターを追加し、その値としてコードチャレンジを含めます。
code_challenge_method
パラメーターはオプションです。ただし特別な理由がない限りは、コードチャレンジメソッドとして後述する S256
の利用が推奨されています。そのため結果的には、S256
を値として指定するために、code_challenge_method
パラメーターも追加することになります。
クライアントアプリは、コードベリファイアの値にコードチャレンジメソッドの計算ロジックを適用して、コードチャレンジの値を導出します。
クライアントアプリが生成しなくてはならないコードベリファイアの値は、[A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~"
からなるランダムな文字列であり、最低43文字、最大128文字の長さが必要となります。
コードチャレンジメソッドの値としては plain
および S256
が定義されています。それぞれの計算ロジックは下記の通りです。
Method | Logic |
---|---|
plain |
code_challenge = code_verifier |
S256 |
code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) |
plain
では、インプットは何ら変換されません。コードベリファイアの値が、そのままコードチャレンジの値となります。
S256
では、SHA-256 のハッシュ値を BASE64-URL エンコードした値を用います。例えば、code_verifier
の値が dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
である場合、code_challenge
の値は E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
となります。
S256
を用いる場合、クライアントアプリは認可リクエストの中に code_challenge_method=S256
を含める必要があります。 code_challenge_method
パラメーターがない場合、認可サーバーは plain
が使われていると判断し、処理します。
認可サーバーは認可コードを生成した後、その値と併せて、認可リクエストに含まれている code_challenge
の値と code_challenge_method
の値を、データベース上に保存します。
認可サーバーはこれらの値を、その後クライアントアプリから送られてくるトークンリクエストの検証に用います。
認可エンドポイントから返されるレスポンス自体は、これまでと同様であり、PKCE 特有のパラメーター等はありません。
認可サーバーから認可コードを受け取った後、クライアントアプリはトークンリクエストを生成します。トークンリクエストには、認可コードに加え、コードチャレンジの値の元となったコードベリファイアの値を、 code_verifier
パラメーターの値として含める必要があります。
PKCE をサポートする認可サーバーは、トークンリクエストに正当なコードベリファイアが含まれているのかを確認します。
この確認は、 grant_type が authorization_code であり、トークンリクエスト中の認可コードがコードチャレンジと紐づいている場合に限ります。
これらの条件がそろっていても、トークンリクエスト中にコードベリファイアが含まれていない場合、そのリクエストは悪意のあるクライアントアプリからのリクエストと認識し、認可サーバーはエラーを返します。
認可サーバーは 2 つのコードチャレンジを照合し、トークンリクエストの正当性を検証します。
コードチャレンジの片方は、認可リクエストに含まれていた(認可サーバーがデータベースに保存しておいた)値です。もう片方は、認可リクエストで指定された方法(トークンチャレンジメソッド)を用いて、トークンリクエスト中のコードベリファイアから計算される値です。
もしこれら 2 つのコードチャレンジが同一の場合、そのトークンリクエストを送信してきたクライアントアプリは、先の認可リクエストの送信元だったクライアントアプリと同一であると、認可サーバーは判断します。一致しない場合、認可サーバーは、そのトークンリクエストが悪意のあるクライアントアプリから来たものと判定します。
トークンリクエストが正規の場合、認可サーバーは通常通りトークンを発行します。
Authlete のアカウントをお持ちでない場合は、まず初めにサインアップしてください。
認可リクエストを実行するためには、サービス API キーと クライアント ID が必要となります。これらはサインアップと同時に発行されています(動作確認用の認可サーバーとクライアントアプリがひとつずつ自動的に生成されています)。
実際の値については、アカウント登録時に送信されるメールの記載や、管理者コンソールおよびクライアントコンソールからご確認ください。
認可サーバー(管理者コンソールのサービス)及びクライアントアプリ (クライアントコンソールのアプリ) の設定は下記を参考にしてください。
Table. Settings of Service in Service Owner Console
カテゴリ | パラメーター | 値 |
---|---|---|
認可 | サポートする認可種別 | 少なくとも AUTHORIZATION_CODE にチェックを入れる |
認可 | サポートする応答種別 | 少なくとも CODE にチェック入れる |
認可 | ダイレクト認可エンドポイントの有効化 | 有効 |
認可 | ダイレクトトークンエンドポイントの有効化 | 有効 |
Table. Settings of Client in Client Developer Console
カテゴリ | パラメーター | 値 |
---|---|---|
基本情報 | クライアントタイプ | PUBLIC を選択する |
認可 | 認可種別 | 少なくとも AUTHORIZATION_CODE にチェックを入れる |
認可 | 応答種別 | 少なくとも CODE にチェック入れる |
認可 | リダイレクト URI | https://api.authlete.com/api/mock/redirection/service-api-key |
下記の URL にブラウザからアクセスしてください。その際、service-api-key と client-id は自身のものに置き換えてください。
https://api.authlete.com/api/auth/authorization/direct/service-api-key
?client_id=client-id
&response_type=code
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
上記にある code_challenge
と code_challenge_method
が、これまで説明してきた PKCE 関連のパラメーターです。コードチャレンジメソッドとして S256
を指定し、コードチャレンジとして、後述するコードベリファイアから計算した値 E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw
を含めています。
認可エンドポイントにおいて、認可ページが表示されます。その中にあるログインフォームに、ここでは動作確認として、ログイン ID としてサービスの API キー、パスワードとして同じく API シークレットを入力し、認可ボタンをクリックしてください。なお、API シークレットの値の確認方法についてはクイックスタートをご参照ください。
認可エンドポイントから返されるレスポンスは、ブラウザを介して、クライアントアプリのリダイレクトエンドポイントに送られます。送信先(リダイレクト URI)は、サインアップ時に自動生成された動作確認用のクライアントアプリの情報として、すでに登録されています。実際の送信先は https://api.authlete.com/api/mock/redirection/service-api-key
になります。
このリダイレクトエンドポイントは、動作確認用に Authlete が用意した実装です。この実装では、認可レスポンスとして受け取った各種パラメーターの値を表示します。たとえば、認可コードを含む認可レスポンスを受け取った場合、リダイレクトエンドポイントはその値を下記のように表示します。
加えて、認可エンドポイントから ID トークンが発行されていた(認可レスポンスに ID トークンを含んでいた)場合、ID トークンの内容を表示します。
また、認可コードフローのような、トークンリクエストを行うフローの場合、トークンリクエストを送信するためのフォームが表示されます。
直前のセクションでも述べましたが、認可レスポンス中に認可コードが含まれている場合、トークンリクエストを送信するためのフォームが表示されます。
そのフォームには、コードベリファイアを入力する欄があります。ここでは、dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
と入力して下さい。
コードベリファイア付きのトークンリクエストを送信するために、「送信」ボタンをクリックしてください。なお、認可コードは 10 分で失効するように設定されているため、10 分以内にボタンをクリックしてください。
認可コードと入力したコードベリファイアが正しい場合、JSON 形式でアクセストークンが返却されます。
{
"access_token": "KPLXrl_wJSHqU708R9kp3bNRGi0LgKUdh0kh-CQhx9g",
"refresh_token": "YLRJXfratV4yq0_65seCT0bF6YxxgU5jKBUvhOZPrb4",
"scope": null,
"token_type": "Bearer",
"expires_in": 86400
}
おめでとうございます!これで、PKCE に対応した認可コードフローでアクセストークンの発行が完了しました。
Authlete では、クライアントに対し、PKCE の利用、およびコードチャレンジメソッド S256 の指定を強制するよう設定可能です。詳細は以下の記事をご参照ください。