OAuth 2.0, Device Flow, OpenID Connect 読書メモ


役に立たないメモです。

## OAuth 2.0 読書メモ

* [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749)
    * [日本語訳](https://openid-foundation-japan.github.io/rfc6749.ja.html)
    * 仕様の本体部分 Framework というだけあって細かい部分は仕様としてまとまらなかったらしい。
    * 1.8.  Interoperability では、この仕様は非互換を生むと居直っている。
* 目的
    * OAuth 2.0 の結果アプリは API にアクセスするための access token を得る。
    * 情報漏洩の可能性をかいくぐって安全に access token を得るのが目的。
* 用語
    * resource owner: ユーザ
    * resource server: 欲しい API を実装しているサーバ
    * client: API を利用するアプリ
    * authorization server: 認証を行うサーバ
* ４つの許可タイプ
    * Authorization Code:
        * ユーザ --- アプリクライアント --- アプリサーバ --- 認証サーバ の形。
        * 秘密の情報をアプリサーバはアプリサーバに置く。
        * まず認証サーバがアプリサーバに authorization code を発行し
            * 次に期限限定の access token を発行する。
            * 場合によっては無期限の refresh token を発行する。
                * refresh token があると新しい access token を発行出来る。
        * アプリクライアントは access token を使って API サーバにアクセスする。
        * アプリクライアントに置いた情報は漏洩の可能性があるので、authorization code や refresh token はアプリサーバが持つ。
        * 疑問: authrization code == refresh token で良いような気がする。
    * Implicit Grant:
        * 最近は public client でも Authorization Code flow を使うように変わってきたのでそのうち無くなる?
            * https://aaronparecki.com/oauth-2-simplified/#single-page-apps
        * ユーザ --- アプリクライアント --- 認証サーバ の形。
        * 認証サーバはアプリクライアントに直接期限限定の access token を発行する。
        * 携帯アプリや OPA 等、アプリサーバを使わない場合、漏洩しては困る情報をアプリに置けない時に使う。
        * 疑問: access token が切れるたびに毎度ログインが必要なので、あまり便利じゃ無さそう。
    * Resource Owner Password Credentials:
        * パスワードを直接認証サーバに伝える形式。
        * パスワード認証後は Authorization Code と同様のフローになる (TBD)
        * そもそもこれを避けるために作られた仕様のはずだが、完全を期すために存在しているのかな?
    * Client Credentials:
        * 認証を行わない。
        * 認証が不要だったり、別途行う API で使う。
* 2. Client Registration:
    * クライアント事前登録で必要な情報
        * client type: こんなの聞かれた気が無い気がする。
            * confidential: 秘密情報を保持出来るサーバを使う場合。
            * public: 秘密情報を保持できない場合。
        * redirection URIs
    * 認証サーバがくれる情報
        * Client Identifier: アプリごとの ID
        * Client Password: BASIC 認証を使っても良い。(非おすすめ)
* 3.  Protocol Endpoints
    * ここでは OAuth 2.0 で使う3つの endpoint を紹介している。抽象的でわかりづらいので 4 章から読んだほうが良い。
    * 3.1. Authorization endpoint
        * アプリは認証が必要になると、認証サーバの endpoint をブラウザで表示する。
    * 3.1.2. Redirection Endpoint (Authorization Response)
        * 認証サーバは認証が完了すると、アプリのこの endpoint へリダイレクトして authorization code をアプリに伝える。
        * Web アプリの場合、ここでサードパーティのライブラリを使っては駄目!
    3.2. Token endpoint
        * アプリは authorization code 取得後、認証サーバのこの endpoint で access token を取得する。
4. Obtaining Authorization: ここから各 endpoint の具体的な記述が始まる。
    * Authorization Endpoint: (GET) client -> auth server
        * 認証なし
        * response_type:
            * "code": authorization code が欲しい時選ぶ
            * "token": access token が欲しい時選ぶ
        * client_id: Authorization code / Implicit Grant で使う。
        * redirect_uri:
        * scope:
        * state: これが無いと悪者のアカウントがリンクされてしまう。(10.12. Cross-Site Request Forgery)
    * Redirection Endpoint (Authorization Response): (GET) auth server -> client
        * 認証なし
        * code: response_type=code の時、authorization code を client に伝える
        * scope: 実際に有効になった scope
        * state: Authorization Endpoint の state と同じ
        * access_token: response_type=token の時 access token を client に伝える
        * expire_in: response_type=token の時有効期限を client に伝える
    * Token endpoint client -> (POST) client -> auth server 
        * Basic 認証(等):
            * Authorization code の時必要
            * Resource Owner Password Credentials Grant で client confidential がある時必要
            * Client Credentials Grant の時必要
        * username: Resource Owner Password Credentials Grant の時必要
        * scope: Resource Owner Password Credentials Grant の時必要
        * リクエストパラメータ
            * grant_type:
                * "authorization_code": Authorization Code の時
                * "passowrd": Resource Owner Password Credentials Grant の時
                * "client_credentials": Client Credentials Grant の時
                * "grant_type": refresh token を使う時
            * code:
                * 認証サーバにもらった authorization code
            * redirect_url:
                * Authorization Endpoint の redirect_url と同じ。
                * 疑問: 何故必要なのか分からない。
            * client_id:
                * Authorization code で Basic 認証等がない場合必要
            * refresh_token: refresh token を使う時
        * レスポンス
            * access_token
            * token_type: access token の使い方
                * `bearer`: ヘッダの `Authorization: Bearer ` の後に token を書く。
                * `mac`: OAuth-HTTP-MAC に従い署名をヘッダ `Authorization: MAC ` に書く。
            * expire_in
            * refresh_token
                * Authorization code か Resource Owner Password Credentials Grant の時だけ
                * もし古い refresh token を持っていたら破棄しないといけない。
        * 認証サーバ側の URL
            * 1. Authorization endpoint: ユーザに認証を促す。
            * 3. Token endpoint: authorization code や refresh token から access token を得る。
        * クライアント側の URL
            * 2. Redirection endpoint: authorization code や access token を得る。
7. Accessing Protected Resources: ccess token の使い方
    * はっきり決まってない。
    * Access token type=bearer:
8. Extensibility: OAuth のパラメータ名などを拡張する方法
    * 11. IANA Considerations に規定された方法で新たに定数を登録提案する。
    * URI や vendor-specific prefix を使う。

* 10.12. Cross-Site Request Forgery
    * 何故 Authorization Endpoint に state が必要なのかの説明。
    * Redirect URI には誰でもアクセス出来るために起こる問題。
    * 攻撃者が自身の authorization code を Redirect URI に渡す。
    * 標的クライアントは攻撃者の authorization code / access token / refresh token を保存してしまう。
    * 標的は気づかないで攻撃者のアカウントに秘密情報を保存してしまう。
    * [OAuth2.0で強制連携させるCSRFの影響と、その対策について](https://subtech.g.hatena.ne.jp/mala/20140724/1406209989)
* 決まってないこと
    * 具体的な access token の送り方が複数ある (https://tools.ietf.org/html/rfc6749#section-7)
    * クライアント認証の方法が複数ある
        * Basic 認証でも Body にパスワードを置いても良い。
        * 他の方法を使っても良い。
    * ユーザ認証の方法。アプリごとに違うので当然か?

## [The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://tools.ietf.org/html/rfc6750) 読書メモ

特に大した情報は無い。

* Bearer Token とは?
    * 持ってるだけで API にアクセス出来るようになる文字列。
    * 対義語は OAuth1 で使われた署名。Bearer token では署名のように正当な所有者である事を証明する必要が無い。
* 2. Authenticated Requests token の送り方
    * 2.1.  Authorization Request Header Field
        * `Authorization: Bearer mF_9.B5f-4.1JqM`
        * のように `Authorization: Bearer ` に続けて書く。
    * 2.2. Form-Encoded Body Parameter
        * `access_token=mF_9.B5f-4.1JqM`
        * のように POST フォームの一部として書く。
    * 2.3. URI Query Parameter
        * `GET /resource?access_token=mF_9.B5f-4.1JqM HTTP/1.1`
        * のように GET クエリパラメータとして書く。
        * セキュリティ上の理由でお薦め出来ない。
        * b64token に + や = が含まれるという意味でもお薦め出来ない。
3.  The WWW-Authenticate Response Header Field
    * 期限切れなど、不正なトークンをもらったサーバの反応の仕方。
    * `HTTP/1.1 401 Unauthorized`
    * `WWW-Authenticate: Bearer realm="example", ...` のようなレスポンスヘッダを返す。


## Device Flow

[OAuth 2.0 Device Flow for Browserless and Input Constrained Device](https://tools.ietf.org/html/draft-ietf-oauth-device-flow-08)

スマート TV のようなブラウザが存在しないデバイスで使うために携帯や PC を使ってアカウントを連携する方法です。

* 1. Introduction
    * デバイスは認証サーバに client identifier を伝える
    * デバイスは認証サーバから以下を受け取る。
        * verification code
        * end-user code
        * end-user verification URI.
    * デバイスはユーザに verification URI を伝えて end-user code を入力してもらう。
    * 認証サーバは end-user code を確認
    * デバイスは認証サーバをポーリングして結果を得る。
* 3. Protocol
    * 3.1.  Device Authorization Request: (POST) デバイス -> 認証サーバ: device_code を要求。
        * Request
            * client_id:
            * scope:
        * Response
            * device_code: デバイスごとのコード。ユーザに見せてはならない。
                * 疑問: 何故必要?
            * user_code: ユーザに見せるコード
            * verification_uri: ユーザに見せる URL
            * verification_uri_complete: user_code を含む URL。QR などに使う。
            * expires_in:
            * interval: ポーリング間隔
    * 3.4. Device Access Token Request: (POST) デバイス -> 認証サーバ: device_code 入力を確認。
        * grant_type: `urn:ietf:params:oauth:grant-type:device_code`
        * device_code:
        * client_id:

参考

* [OAuth for Browserless and Input-Constrained Devices](https://www.oauth.com/oauth2-servers/device-flow/)

## [OpenID Connect](http://openid.net/connect/)

これは RFC ではない。

* OAuth 2.0 では決まっていない identity information の取得方法をまとめた仕様。
    * OAuth 2.0: ある API にアクセスするための access token を得る仕組み。
    * OpenID Connect: OAuth 2.0 で認証したユーザが誰なのかを特定する API の標準化。
* OAuth 2.0 scope に "openid" を含める
* ID Token と呼ばれる Json Web Token (JWT) によって個人特定を実現している。
* OpenID Providers (OPs): OpenID Connect を実装している認証サーバの事。
* Relying Parties (RPs): OpenID Connect を使っているクライアントの事。
* [OpenID Connect Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html):
    * Authorization Endpoint や Token Endpoint を見つけるプロトコル。
    * 例: https://accounts.google.com/.well-known/openid-configuration
* [OpenID Connect Dynamic Client Registration 1.0](http://openid.net/specs/openid-connect-registration-1_0.html)
    * クライアント登録を行う方法
    * 疑問: 機械的にクライアントを登録するユースケースとなるとスパムボット作成くらいしか思いつかない。何故こんな物があるのか?
* ID Token
    * ユーザの特定に使う。復号するとJSON 形式になる。
    * iss: 発行母体の URL。
    * sub: 発行母体で一意の識別子。
    * その耐いろいろ。
    * iss と sub がグローバルに一意になるはず。
* [OAuth 2.0 Multiple Response Type Encoding Practices](http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html)
    * OpenID Connect で追加された response_type (code / token 以外) について書いてあるらしい。
    * 要調査
* OAuth 2.0 の Token Endpoint (implicit の場合 authorization endpoint) の response として、追加で id_token が返る。内容は JWT。
* 5.3.  UserInfo Endpoint (GET)
    * ユーザの個人情報を取得する API
    * 名前、名字、email、写真などを取得出来る。