メインコンテンツへスキップ
このページは Authlete 3.0 用です。2.x についてはこちらのページをご覧ください。

1. イントロダクション

RFC 7636: Proof Key for Code Exchange (PKCE, 「ピクシー」と発音します) は、 認可コード横取り攻撃(authorization code interception attack) への対策に関する仕様です。 authorization code interception attack 2015 年 9 月に公開された同仕様は、認可コードフローの各種リクエストに関し、いくつかの追加パラメーターを定義しています。
  1. 認可リクエスト: code_challenge パラメーターと code_challenge_method パラメーターを追加
  2. トークンリクエスト: code_verifier パラメーターを追加
この仕様により認可サーバーは、悪意のある(正当なコードベリファイアを持たない)クライアントアプリからのトークンリクエストを拒否できるようになります。

2. PKCE 認可リクエスト

2.1 リクエストパラメーター

PKCE に対応したクライアントアプリは、認可リクエストに code_challenge パラメーターを追加し、その値としてコードチャレンジを含めます。 code_challenge_method パラメーターはオプションです。ただし特別な理由がない限りは、コードチャレンジメソッドとして後述する S256 の利用が推奨されています。そのため結果的には、S256 を値として指定するために、code_challenge_method パラメーターも追加することになります。

2.2 コードチャレンジ

クライアントアプリは、コードベリファイアの値にコードチャレンジメソッドの計算ロジックを適用して、コードチャレンジの値を導出します。

2.3 コードベリファイア

クライアントアプリが生成しなくてはならないコードベリファイアの値は、[A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~" からなるランダムな文字列であり、最低43文字、最大128文字の長さが必要となります。 pkce authorization request

2.4 コードチャレンジメソッド

コードチャレンジメソッドの値としては plain および S256 が定義されています。それぞれの計算ロジックは下記の通りです。 plain では、インプットは何ら変換されません。コードベリファイアの値が、そのままコードチャレンジの値となります。 S256 では、SHA-256 のハッシュ値を BASE64-URL エンコードした値を用います。例えば、code_verifier の値が dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk である場合、code_challenge の値は E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM となります。 S256 を用いる場合、クライアントアプリは認可リクエストの中に code_challenge_method=S256 を含める必要があります。 code_challenge_method パラメーターがない場合、認可サーバーは plain が使われていると判断し、処理します。

3. PKCE 認可レスポンス

認可サーバーは認可コードを生成した後、その値と併せて、認可リクエストに含まれている code_challenge の値と code_challenge_method の値を、データベース上に保存します。 認可サーバーはこれらの値を、その後クライアントアプリから送られてくるトークンリクエストの検証に用います。 認可エンドポイントから返されるレスポンス自体は、これまでと同様であり、PKCE 特有のパラメーター等はありません。 pkce authorization response

4. PKCE トークンリクエスト

認可サーバーから認可コードを受け取った後、クライアントアプリはトークンリクエストを生成します。トークンリクエストには、認可コードに加え、コードチャレンジの値の元となったコードベリファイアの値を、 code_verifier パラメーターの値として含める必要があります。 pkce_token_request

5. PKCE トークンレスポンス

5.1 コードベリファイアの有無を確認する

PKCE をサポートする認可サーバーは、トークンリクエストに正当なコードベリファイアが含まれているのかを確認します。 この確認は、 grant_type が authorization_code であり、トークンリクエスト中の認可コードがコードチャレンジと紐づいている場合に限ります。 これらの条件がそろっていても、トークンリクエスト中にコードベリファイアが含まれていない場合、そのリクエストは悪意のあるクライアントアプリからのリクエストと認識し、認可サーバーはエラーを返します。

5.2 コードベリファイアを検証する

認可サーバーは 2 つのコードチャレンジを照合し、トークンリクエストの正当性を検証します。 コードチャレンジの片方は、認可リクエストに含まれていた(認可サーバーがデータベースに保存しておいた)値です。もう片方は、認可リクエストで指定された方法(トークンチャレンジメソッド)を用いて、トークンリクエスト中のコードベリファイアから計算される値です。 もしこれら 2 つのコードチャレンジが同一の場合、そのトークンリクエストを送信してきたクライアントアプリは、先の認可リクエストの送信元だったクライアントアプリと同一であると、認可サーバーは判断します。一致しない場合、認可サーバーは、そのトークンリクエストが悪意のあるクライアントアプリから来たものと判定します。

5.3 トークンを発行する

トークンリクエストが正規の場合、認可サーバーは通常通りトークンを発行します。 pkce_token_response

6. PKCE を試す

6.1 準備する

6.1.1 サインアップする

Authlete のアカウントをお持ちでない場合は、まずサインアップしてください。5 分程度で完了します。 登録オプションを表示するサインアップページ: GoogleおよびGitHubソーシャルログインボタン、およびメールアドレスサインアップフィールド

6.1.2 Service ID と Client ID

認可リクエストを実行するためには、Service ID と Client ID が必要です。 サービスとクライアントをまだ作成していない場合は、サンプル認可サーバーのセットアップの手順に従って作成してください。 作成済みの Service ID と Client ID は、Authlete 管理コンソールで確認できます。

6.1.3 サービスとクライアントの設定

サービスとクライアントを以下のように設定します。 Table. サービスの設定 サービスを設定します:
  1. 「サービス設定」>「エンドポイント」>「基本設定」>「一般」を開きます。
  2. 「サポートするグラントタイプを選択」で AUTHORIZATION_CODE を選択します。
  3. 「レスポンスタイプを選択」で CODE を選択します。
  4. 「変更を保存」をクリックして変更を適用します。
サービスの「エンドポイント」>「基本設定」画面でサポートするグラントタイプとレスポンスタイプを選択したところ Table. クライアントの設定 クライアントの基本設定を行います:
  1. 「クライアント設定」>「基本設定」>「一般」を開きます。
  2. 「クライアントタイプ」で「公開」を選択します。
  3. 「リダイレクトURI」で「追加」をクリックし、クライアントがレスポンスを受け取る URI を登録します。本ページでは https://client.example.org/cb/example.com を使用します。
  4. 「変更を保存」をクリックして変更を適用します。
クライアントの「基本設定」画面でクライアントタイプに「公開」を選択したところ クライアントの「基本設定」画面のリダイレクトURI クライアントのエンドポイント設定を行います:
  1. 「クライアント設定」>「エンドポイント」>「基本設定」>「一般」を開きます。
  2. 「認可タイプを選択」で AUTHORIZATION_CODE を選択します。
  3. 「レスポンスタイプを選択」で CODE を選択します。
  4. 「変更を保存」をクリックして変更を適用します。
クライアントの「エンドポイント」>「基本設定」画面でサポート可能な認可タイプとレスポンスタイプを選択したところ

6.2. 認可リクエスト

6.2.1. 認可エンドポイントへのリクエスト

OAuth 2.0 の基礎で説明したとおり、Authlete の認可 API は、認可サーバーが受け取った認可リクエストを認可サーバーに代わって検証します。認可サーバーから Authlete API への認可リクエストは、以下の curl コマンドで実行できます。<Service ID>、<Service Access Token>、<Client ID> は自身の値に置き換えてください。
parameters に含めている code_challenge と code_challenge_method が、これまで説明してきた PKCE 関連のパラメーターです。コードチャレンジメソッドとして S256 を指定し、コードチャレンジとして、後述するコードベリファイアから計算した値を含めています。

6.2.2 認可レスポンス

リクエストが正当な場合、Authlete は以下のようなレスポンスを返します。
リソースオーナーの認証と同意の取得が済んでいるものとして、認可サーバーは認可コードを取得するために /auth/authorization/issue API を呼び出します。以下の curl コマンドを実行してください。<Service ID>、<Service Access Token>、<Ticket> は自身の値に置き換えてください。
リクエストが正当な場合、Authlete は以下のようなレスポンスを生成します。

6.3 トークンリクエスト

6.3.1 curl によるトークンリクエスト

認可サーバーがユーザーエージェントにリダイレクトレスポンスを返し、ユーザーエージェントがクライアントに対して以下の HTTP GET リクエストを送信したものとします。
トークンリクエストは以下の curl コマンドで実行できます。<Service ID>、<Service Access Token>、<Client ID>、<Code> は自身の値に置き換えてください。code_verifier には、6.2.1 のコードチャレンジのもとになったコードベリファイアを指定します。

6.3.2. トークンレスポンス

認可コードとコードベリファイアが正しい場合、JSON 形式でアクセストークンが返却されます。
リフレッシュトークンは、サービスとクライアントの双方でリフレッシュトークングラントが許可されている場合に発行されます。どちらかで許可されていない場合、レスポンスに refreshToken は含まれません。 おめでとうございます!これで、PKCE に対応した認可コードフローでアクセストークンの発行が完了しました。

6.4. PKCE の設定

Authlete には PKCE に関する設定項目があり、サービスとクライアントのそれぞれで有効化できます。

サービスの PKCE 設定

サービス設定で PKCE を有効にします:
  1. 「サービス設定」>「エンドポイント」>「認可」>「一般」を開きます。
  2. 「認可コード交換用証明キー(PKCE)」で「PKCEを必須にする」と「コードチャレンジメソッドに対してS256を必須にする」を有効にします。
  3. 「変更を保存」をクリックして変更を適用します。
「サービス設定」の「エンドポイント」>「認可」>「一般」にある PKCE の設定項目

クライアントの PKCE 設定

クライアント設定で PKCE を有効にします:
  1. 「クライアント設定」>「エンドポイント」>「認可」>「一般」を開きます。
  2. 「認可コード交換用証明キー(PKCE)」で「PKCEを必須にする」と「コードチャレンジメソッドとしてS256を使うことを必須にする」を有効にします。
  3. 「変更を保存」をクリックして変更を適用します。
「クライアント設定」の「エンドポイント」>「認可」>「一般」にある PKCE の設定項目 「PKCEを必須にする」が有効な場合、認可コードフローを用いる認可リクエストでは code_challenge パラメーターが常に必須となります。既定値は無効です。 設定手順の詳細は以下のページをご参照ください。