認可コードと PKCE デベロッパ

最終更新:2026年8月16日

認可コードと PKCE

ポータルで作成したアプリは Authorization Code + PKCE(S256) フローを使います。ブラウザが受け取るのは短命な認可コード code だけです。code_verifier は信頼できる環境に保存し、トークン交換に使います。機密クライアントはさらにバックエンドで client_secret を使います。JWT アサーションクライアントはさらにバックエンドで client_assertion に署名します。

本番 Issuer の例:

ISSUER=https://api-passport.swaymoon.com

実際のエンドポイントは {ISSUER}/.well-known/openid-configuration のディスカバリ文書に従ってください。

1. PKCE を生成する

  1. 高エントロピーの code_verifier を生成します(43–128 の URL 安全文字)。
  2. code_challenge = BASE64URL(SHA256(code_verifier))(パディングなし)。
  3. code_challenge_method = S256

code_verifierstate はサーバーセッション、暗号化 Cookie、または非機密クライアントが使える安全なセッション保存に置いてください。第三者スクリプトへ漏らさないでください。

2. ユーザーを認可へ案内する

認可エンドポイントを組み立ててリダイレクトします。例:

GET /oauth2/authorize?
  response_type=code
  &client_id=swm_xxxxxxxx
  &redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
  &scope=openid%20name%20picture%20email
  &state=RANDOM_STATE
  &code_challenge=CHALLENGE
  &code_challenge_method=S256
Host: api-passport.swaymoon.com
パラメータ要件
response_type常に code
client_idデベロッパポータルが発行
redirect_uri登録済みで完全一致が必須
scope空白区切り。少なくとも openid
stateCSRF 防止。コールバック時に元の値と一致するか検証
code_challenge / code_challenge_method必須S256

ユーザーは必要なら passport.swaymoon.com でサインインし、認可を確認します。成功後、ブラウザは次へ遷移します:

https://app.example.com/callback?code=...&state=...

ユーザーが認可をキャンセルした場合、アプリは通常使える code を受け取りません。返されたエラーやキャンセルパラメータに従って処理してください。

3. 認可コードをトークンに交換する

トークンエンドポイントへ POST します(application/x-www-form-urlencoded)。

機密クライアント

バックエンドで HTTP Basic を使います:

POST /oauth2/token
Host: api-passport.swaymoon.com
Authorization: Basic BASE64(urlencode(client_id):urlencode(client_secret))
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=AUTHORIZATION_CODE
&redirect_uri=https://app.example.com/callback
&code_verifier=VERIFIER

非機密クライアント

Basic も client_secret送らないでください。フォームに client_id を含めます:

POST /oauth2/token
Host: api-passport.swaymoon.com
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=AUTHORIZATION_CODE
&redirect_uri=https://app.example.com/callback
&client_id=swm_xxxxxxxx
&code_verifier=VERIFIER

JWT アサーションクライアント

Basic も client_secret送らないでくださいバックエンドで、登録した公開鍵に対応する秘密鍵で client_assertion に署名し、フォームに含めます:

POST /oauth2/token
Host: api-passport.swaymoon.com
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=AUTHORIZATION_CODE
&redirect_uri=https://app.example.com/callback
&client_id=swm_xxxxxxxx
&code_verifier=VERIFIER
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=SIGNED_JWT

client_assertionES256 で署名した JWT です。JWS ヘッダの kid はポータルに登録した公開鍵と一致させてください。ペイロードのクレーム:

クレーム
issあなたの client_id
subあなたの client_idiss と同じ)
audディスカバリ文書の token_endpoint(本番は通常 https://api-passport.swaymoon.com/oauth2/token
jtiリクエストごとに新しい一意の値
iat発行時刻
exp有効期限(数分以内を推奨。未来であること)

秘密鍵はサーバーにだけ置きます。ポータルは秘密鍵 JWK を受け付けません。実行できる curl / Python 断片は「例とトラブルシューティング」を参照してください。

補足:

  • redirect_uri は認可リクエストの値と一致させる必要があります。
  • code_verifier は認可時に送った code_challenge に対応している必要があります。
  • 認可コードは一度きりで、有効期間は短いです。

成功レスポンスの例(フィールドは実際の応答に従います):

{
  "access_token": "...",
  "refresh_token": "...",
  "id_token": "...",
  "token_type": "Bearer",
  "expires_in": 300,
  "scope": "openid name picture email"
}
  • 機密クライアントJWT アサーションクライアントは通常 refresh_token を受け取ります。トークンはすべて安全に保管し、client_secret、秘密鍵、Refresh Token を信頼できないフロントへ渡さないでください
  • 非機密クライアントの応答に refresh_tokenありません。Access Token が切れたら、認可コード + PKCE をやり直してください。

4. アクセストークンの更新(機密と JWT アサーション)

Access Token の期限切れ後、機密クライアント:

POST /oauth2/token
Authorization: Basic ...
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=REFRESH_TOKEN

JWT アサーションクライアントの更新でも Basic は使いません。新しい client_assertion を署名して送ります:

POST /oauth2/token
Host: api-passport.swaymoon.com
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=REFRESH_TOKEN
&client_id=swm_xxxxxxxx
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=SIGNED_JWT

更新が成功したら、新しい access_token と、応答でローテーションされる可能性のある refresh_token を使ってください。トークンローテーションでは古い Refresh Token がすぐ無効になることがあります。常に最新の応答を正としてください。

非機密クライアントはこの手順をサポートしません。

5. UX の要点

  • 未サインインのユーザーは先にアカウントのサインインページへ行き、その後認可確認に進みます。
  • 機微な操作では再サインイン(step-up authentication)が求められることがあります。想定どおりのセキュリティです。
  • 同意ページの文言と任意権限のチェックは「権限と同意」を参照してください。

6. セキュリティチェックリスト

  • 常に code_verifierstate を保存して検証する。
  • 機密クライアント:client_secret でのトークン交換はバックエンドのみ。
  • JWT アサーションクライアント:client_assertion の署名はバックエンドのみ。秘密鍵と kid はポータルに登録した公開鍵と対応させる。
  • 非機密クライアント:client_secret を捏造・ハードコードしない。PKCE と登録済み Redirect URI に依存する。
  • コールバックと通信は HTTPS。
  • scope は必要最小限。
  • invalid_grantinvalid_clientinvalid_request などのエラーを適切に扱う。

次のステップ:「トークンとユーザー情報」を読み、トークン検証とローカルユーザー作成を完了してください。