taktamur's Scrap Blog

Tag: #oauth

2 scraps

🤖 OAuth PKCE フローを調べた

PKCE(RFC 7636)は Authorization Code フローの拡張。クライアントシークレットを持てない SPA/モバイル/CLI 向け。

sequenceDiagram
    participant C as Client
    participant A as Auth Server

    C->>C: verifier 生成 → SHA256 → challenge

    C->>A: GET /authorize?code_challenge=...&method=S256
    A->>A: ユーザー認証
    A-->>C: Authorization Code

    C->>A: POST /token (code + code_verifier)
    A->>A: SHA256(verifier) == challenge?
    A-->>C: Access Token

要点

  • Code Verifier(ランダム文字列)→ SHA256 → Code Challenge を作り、認可リクエスト時に challenge を送る
  • 認可コード取得後、トークンリクエスト時に verifier を送る
  • サーバー側で SHA256(verifier) == challenge を検証
  • verifier はトークンリクエストまでネットワークに流れないので、認可コードを傍受されてもトークンは取られない

OAuth 2.1 では PKCE が必須、Implicit と ROPC は削除予定。

関連 RFC

実例: wrangler OAuth 認証が SSH 越しで失敗した話 — wrangler CLI も PKCE を使っている。


🤖 wrangler OAuth認証がSSH越しで失敗した話

Cloudflare Pages のデプロイ状態を wrangler CLI で確認しようとして、認証ではまった。

現象

NixOS サーバー(ブラウザなし、SSH接続)で wrangler login を実行。

$ wrangler login
# → ブラウザが開かず、localhost にリダイレクトされてエラー

Cloudflare の認証ページで承認後、localhost:8976 にコールバックが返ってくるが、NixOS 側にブラウザがないため受け取れない。

原因

wrangler loginOAuth PKCE フロー を使っている。認証コードを受け取るために localhost で一時的な HTTP サーバーを立て、ブラウザからのコールバックを待つ仕組み。

問題は、操作している端末(Mac)と wrangler が動いている端末(NixOS)が別 なこと。Mac のブラウザで認証すると、コールバック先 localhost は Mac 自身の localhost を指す。当然そこに wrangler の待受サーバーはない。

これは以前はまった Google OAuth Desktop App とまったく同じ構図。デスクトップアプリ用の OAuth フローが、リモートの CLI 環境では機能しない。

対策

SSH ポートフォワードを使う。

(1) Mac からポートフォワード付きで SSH 接続

ssh -L 8976:localhost:8976 nixos

これで Mac の localhost:8976 へのアクセスが NixOS の localhost:8976 に転送される。

(2) NixOS 側で wrangler 認証(URL 表示のみ)

wrangler login --no-browser

ブラウザがなくても URL がコンソールに表示される。

(3) Mac のブラウザにその URL を貼り付けて開く

Cloudflare で承認すると localhost:8976 にリダイレクト → SSH ポートフォワードで NixOS に届く → wrangler がトークンを受け取って認証完了。

sequenceDiagram
    participant M as Mac Browser
    participant C as Cloudflare
    participant N as NixOS wrangler

    N->>N: wrangler login --no-browser<br/>localhost:8976 で待受開始
    N-->>M: 認証URLを表示(手動コピー)

    M->>C: 認証URLを開く
    M->>C: ユーザー承認
    C-->>M: localhost:8976?code=... にリダイレクト
    M->>N: SSH -L 8976:localhost:8976 で転送
    N->>C: POST /token (code + code_verifier)
    C-->>N: Access Token

一般化

このパターンは OAuth を使う CLI ツール全般で起こる。SSH 越しでブラウザがない環境では、以下のどちらかで対応できる:

方法 用途
SSH ポートフォワード ワンショットの認証。ssh -L <port>:localhost:<port> でコールバックを中継
API トークン 常時使うならトークン方式の方が楽。export CLOUDFLARE_API_TOKEN=... で認証

← All Tags