Open4

OAuth 2.0 for First-Party Applications

yapooyapoo

OAuth 2.0 for First-Party Applications (draft-parecki-oauth-first-party-apps-01)

概要

OAuth 2.0 でアクセストークンを得る方法として最も一般的なものに認可コードフローがある。これはブラウザを用いてリソースオーナーと認可サーバーがやり取りする必要があり、これはクライアントがネイティブアプリの場合には (アプリに閉じた体験にならないことから) あまり良くない体験であると思われる。

そこで本仕様ではクライアントが First-Party のネイティブアプリの場合に、クライアントが直接ユーザー (リソースオーナー) とやりとりして認可サーバーの Authorization Challenge Endpoint (本仕様で導入される) へ通知し、そのレスポンスとして認可コードを得る手順が定められている。

この仕様はクライアントが First-Party である場合、すなわち認可サーバーとクライアントが同一の Entity により運営されており、それがユーザーにとってもわかるような場合にのみ利用可能であり、それ以外の場合には用いてはならない。

なお、First-Party アプリが複数あり、それらが同一の端末にインストールされていることが期待される場合は、各アプリでこの仕様を実装するのではなく OpenID Connect Native SSO を実装する方が、ユーザーによるインタラクションが 1 回で済むことから望ましい。

以下に処理のフローを示す。

yapooyapoo

Authorization Challenge Endpoint

Authorization Challenge Request

クライアントは認証等に必要な情報 (パスワードや Passkeys のレスポンス、MFA コードなど) をアプリ上で収集して Authorization Challenge Endpoint へ送る。

このエンドポイントは POST リクエストにのみ対応し、リクエストボディの Content-Type は application/x-www-form-urlencoded である。当該クライアントがトークンエンドポイントでクライアント認証を求めるものの場合、当エンドポイントでもクライアント認証を行う。また、リクエストボディのパラメータとしては認可エンドポイントのすべてのリクエストパラメータをサポートするので、PKCE[1] や Resource Inditacot [2]OpenID Connect などを利用することも可能である。ただし response_mode=query など本仕様においては無意味なパラメータが指定された場合に認可サーバーがどのように振る舞うべきであるかは本仕様では示されない。

本エンドポイントではリクエストパラメータとして以下の追加 / 仕様変更がある。また、必要に応じて独自のリクエストパラメータ (パスワード、Passkeys のレスポンスなどのためのもの) を導入してもよい。

parameters description
client_id クライアント認証をせず、かつ auth_session を指定しない場合は必須
acr_values 任意。認証コンテキストリファレンス[3]
auth_session それまでの Authorization Challenge Response ですでに auth_session を受け取っていれば必須

以下は Section 5.1 に記載のリクエストの例である。

POST /authorize HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

login_hint=%2B1-310-123-4567&scope=profile
&client_id=bb16c14c73415

レスポンス

成功レスポンス

このとき認可コードが返却される。以下はレスポンスの例である。

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store

{
  "authorization_code": "uY29tL2F1dGhlbnRpY"
}

ブラウザを用いた通常の認可コードフローに乗せたい場合

このとき Pushed Authorization Request (PAR)[4] の Pushed Authorization Request Endpoint における request_uri が返却される。この request_uri はAuthorization Challenge Request で指定していたリクエストパラメータに紐づく。PAR では request_uri は有効期限があったが本仕様では今のところ記載がない。

request_uri はクライアントにとってはオペークな値で、 urn:ietf:params:oauth:request_uri:<reference-value> の形式である。

以下はレスポンスの例である

HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-cache, no-store

{
 "error": "redirect_to_web",
 "request_uri": "urn:ietf:params:oauth:request_uri:6esc_11ACC5bwc014ltc14eY22c",
 "expires_in": 600
}

クライアントはこの request_uri パラメータを用いて認可エンドポイントにリクエストすることで、通常のブラウザにおける認可コードフローを開始する。以下は認可リクエストの例である。

GET /authorize?client_id=s6BhdRkqt3&request_uri=urn%3Aietf%3Aparams
  %3Aoauth%3Arequest_uri%3A6esc_11ACC5bwc014ltc14eY22c HTTP/1.1
Host: as.example.com

エラーレスポンス

仕様にはそのように記載されてはいないが、エラーレスポンスは RFC 6749 Section 5.2 で示されるトークンエンドポイントのエラーレスポンスと同様であるが、以下のパラメータが新規に追加される。

parameter description
auth_session クライアントはここで受け取った値を以降の Authorization Challenge Request で指定しなければならない。これによって以降の Authorization Challenge Request を関連付けることができる。これはクライアントにとってはオペークな値であり、Authorization Challenge Response によって更新される場合もある[5]

認可サーバーはクライアントに要求する情報がある場合は、その内容に応じて error レスポンスパラメータを自由に定義して返却しなければならない。

脚注
  1. RFC 7636 ↩︎

  2. RFC 8707 ↩︎

  3. OpenID Connect Core Section 3.1.2.1 や OAuth 2.0 Step Up Authentication Challenge Protocol (RFC 9470) でも導入されている ↩︎

  4. RFC 9126 ↩︎

  5. たとえばこれを JWE にする場合などは毎回値が変わることがあり得る ↩︎

yapooyapoo

トークンエンドポイント

トークンエンドポイントで認可コードと引き換えにアクセストークンや ID トークンを得る。ここでトークンリクエストは RFC 6749 Section 4.1.3 で定義されたものと同様だが、redirect_uri は指定しない。

レスポンスも RFC 6749 Section 4.1.4 (成功レスポンス) や同 Section 5.2 (エラーレスポンス) で定義されたものと同様だが、リクエストパラメータとして auth_session が追加される。

以下は Section 6.1 に記載の成功レスポンスの例である。

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{
  "access_token": "2YotnFZFEjr1zCsicMWpAA",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA",
  "auth_session": "uY29tL2F1dGhlbnRpY"
}

以下は同様にエラーレスポンスの例である。

HTTP/1.1 403 Forbidden
Content-Type: application/json
Cache-Control: no-store

{
  "error": "authorization_required",
  "auth_session": "uY29tL2F1dGhlbnRpY"
}
yapooyapoo

所感

さすがにパスワード認証でこれを使うのはどうかと思うが、Passkeys 認証ではこの仕様を使うことでアプリでの認証体験を向上させることができそう。