satoshi.inoue's blog

備忘録を兼ねているので、薄い内容の投稿もあります。

OAuth2.0について改めて調べてみた

スポンサードリンク

OAuth2.0とは、Webアプリケーション等に特定の認可フローを提供しながら、クライアント開発者の簡潔さに焦点を合わせている業界標準の認可プロトコルです。

1 認可コードフロー(Authorization Code Flow)

4.1. Authorization Code Grantで定義されているフロー。
認可サーバーがクライアントとリソースオーナーの仲介となって発行する。
リソースオーナーへ直接認可を要求する代わりに、クライアントはリソースオーナーを認可サーバーへリダイレクトさせ、リソースオーナーがリダイレクトして戻ってきた際に認可コードを取得する。
リソースオーナーを認可コードとともにリダイレクト経由でクライアントに戻す前に、認可サーバーはリソースオーナーを認証し認可を得る。
これによりリソースオーナーは認可サーバーによってのみ認証され, リソースオーナーのクレデンシャルはクライアントへ共有されない。
認可コードはクライアントを認証する機会を提供したり、リソースオーナーのユーザーエージェントを経由せずアクセストークンをクライアントに直接送信できるなど、いくつかの点で重要なセキュリティ的なメリットを提供する。
リソースオーナーのユーザーエージェントを経由してデータを送信した場合、そのデータはリソースオーナーを含む第三者に露出する可能性がある。
f:id:acquapazza:20181219030546p:plain

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

https://tools.ietf.org/html/rfc6749#section-4.1.1

GET {認可エンドポイント}
    ?response_type=code // 必須 codeを指定
    &client_id={クライアントID} // 必須 
    &redirect_uri={リダイレクトURI} // 任意
    &scope={スコープ群} // 任意
    &state={任意文字列} // 推奨
    HTTP/1.1
Host: {認可サーバー}

1.2 認可エンドポイントからのレスポンス

https://tools.ietf.org/html/rfc6749#section-4.1.2

HTTP/1.1 302 Found
Location: {リダイレクトURI}
    ?code={認可コード} // 必須
    &state={任意文字列} // 認可エンドポイントへのリクエストにstateが含まれている場合は必須

1.3 トークンエンドポイントへのリクエス

https://tools.ietf.org/html/rfc6749#section-4.1.3

POST {トークンエンドポイント} HTTP/1.1
Host: {認可サーバー}
Authorization: Basic {Basic認証パスワード} // クライアントパスワードを所有している場合
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code // 必須 authorization_codeを指定
&code={認可コード} // 必須 認可エンドポイントのレスポンスのcodeを指定
&redirect_uri={リダイレクトURI} // 認可エンドポイントへのリクエストにredirect_uriが含まれている場合は必須

条件によってはクライアント認証を求められることがあり、その場合はBasic認証の代わりにclient_id & client_secretを使用するのも可能。

クライアントの種類が機密である場合、クライアントと認可サーバーは認可サーバーのセキュリティ要件に適したクライアント認証方法を確立します。 認可サーバは、そのセキュリティ要件を満たすあらゆる形式のクライアント認証を受け入れてもよい(MAY)。

機密クライアントは、通常、認証サーバとの認証に使用される一組のクライアント証明書(例えば、パスワード、公開鍵/秘密鍵のペア)を発行(または確立)する。

認可サーバは、パブリッククライアントとのクライアント認証方法を確立してもよい(MAY)。 しかしながら、認可サーバーはクライアントを識別するために公開クライアント認証に頼ってはいけません(MUST NOT)。

クライアントは各要求で複数の認証方法を使用してはなりません(MUST NOT)。

1.4 トークンエンドポイントからのレスポンス

https://tools.ietf.org/html/rfc6749#section-4.1.4

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

{
    "access_token":{アクセストークン}, // 必須
    "token_type":{トークンタイプ}, // 必須
    "expires_in":{有効秒数}, // 任意
    "refresh_token":{リフレッシュトークン}, // 任意
    "scope":{スコープ群} // 認可エンドポイントへのリクエストと差異がある場合は必須
}

2 インプリシットフロー(Implicit Grant Flow)

4.2. Implicit Grantで定義されているフロー。
インプリシットグラントは, 認可コードフローを単純化したものであり、JavaScriptの様なスクリプト言語を使用してブラウザ上で実行されるクライアントに最適化されている。
インプリシットフローでは, クライアントは (リソースオーナー認可の結果) 認可コードの代わりに直接アクセストークンを受け取る。
このグラントタイプは (認可コードのように後にアクセストークンを取得する際に用いられる) 仲介のクレデンシャルを利用しないため、インプリシット (訳注: implicit = 暗黙の) と呼ばれる。
インプリシットグラントフローでアクセストークンを発行する場合、認可サーバーはクライアントを認証しない。
ただし、クライアントにアクセストークンを渡す際に使用されるリダイレクトURIをもとに、クライアントの身元が検証可能なこともある。
アクセストークンはリソースオーナー、もしくはリソースオーナーのユーザーエージェントにアクセスすることで他のアプリケーションに晒される可能性がある。
アクセストークンを得るのに必要な往復の回数を減らせるため、インプリシットグラントは (ブラウザにおけるアプリケーションとして実行されたクライアントなど) いくつかのクライアントで応答性と効率性を高める。
しかしながら特に認可コードグラントタイプが利用可能である場合、インプリシットグラントを用いた場合の利便性はセキュリティー面の影響とトレードオフの関係にあることを考慮すべきである。
リフレッシュトークンは発行されません。
f:id:acquapazza:20181220022819p:plain

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

https://tools.ietf.org/html/rfc6749#section-4.2.1

GET {認可エンドポイント}
    ?response_type=token // 必須 token指定
    &client_id={クライアントID} // 必須
    &redirect_uri={リダイレクトURI} // 任意
    &scope={スコープ群} // 任意
    &state={任意文字列} // 推奨
    HTTP/1.1
Host: {認可サーバー}

2.2 認可エンドポイントからのレスポンス

https://tools.ietf.org/html/rfc6749#section-4.2.2

HTTP/1.1 302 Found
Location: {リダイレクトURI}
    #access_token={アクセストークン} // 必須
    &token_type={トークンタイプ} // 必須
    &expires_in={有効秒数} // 任意
    &state={任意文字列} // 認可エンドポイントへのリクエストにstateが含まれている場合は必須
    &scope={スコープ群} // 認可エンドポイントへのリクエストと差異がある場合は必須

3 リソースオーナー・パスワード・クレデンシャルズフロー(Resource Owner Password Credentials Flow)

4.3. Resource Owner Password Credentials Grantで定義されているフロー。
トークンエンドポイントにトークンリクエストを投げ、応答としてアクセストークンを受け取る。
OAuthのフローですが、クライアントアプリケーションがユーザーの ID とパスワードを受けとります。

リソースオーナーパスワードクレデンシャル (例えばユーザー名とパスワード) を直接アクセストークンを得るための認可グラントとして使用することも出来る。
このクレデンシャルは、(例えばクライアントがデバイスOSの一部となっていたり、非常に特権のあるアプリケーションである場合のように) リソースオーナーとクライアントの間で高い信頼があり、(認可コードのような) 他の認可グラントタイプが利用できない場合のみ使用されるべきである。
このグラントタイプでは、クライアントがリソースオーナークレデンシャルへ直接アクセスすることになるが、リソースオーナークレデンシャルは一度きりのリクエストにのみ使用され、アクセストークンに交換される。
このグラントタイプでは、クレデンシャルを寿命の長いアクセストークンやリフレッシュトークンと交換することにより、クライアントがリソースオーナークレデンシャルを後の利用のために保存しておく必要がなくなる。
f:id:acquapazza:20181220022836p:plain

3.1 トークンエンドポイントへのリクエス

https://tools.ietf.org/html/rfc6749#section-4.3.2

POST {トークンエンドポイント} HTTP/1.1
Host: {認可サーバー}
Authorization: Basic {Basic認証パスワード} // クライアントパスワードを所有している場合
Content-Type: application/x-www-form-urlencoded

grant_type=password // 必須 password指定
&username={ユーザー名} // 必須
&password={パスワード} // 必須
&scope={スコープ群} // 任意

Basic認証の代わりにclient_id & client_secretを使用するのも可能。

3.2 トークンエンドポイントからのレスポンス

https://tools.ietf.org/html/rfc6749#section-4.3.3

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

{
    "access_token":{アクセストークン}, // 必須
    "token_type":{トークンタイプ}, // 必須
    "expires_in":{有効秒数}, // 任意
    "refresh_token":{リフレッシュトークン}, // 任意
    "scope":{スコープ群} // トークンエンドポイントへのリクエストと差異がある場合は必須
}

4 クライアント・クレデンシャルズフロー(Client Credentials Flow)

4.4. Client Credentials Grant定義されているフロー。
トークンエンドポイントにトークンリクエストを投げ、応答としてアクセストークンを受け取る。
このフローでは、ユーザーの認証はおこなわれず、クライアントアプリケーションの認証のみがおこなわれる。
認可範囲がクライアントの管理下にある保護されたリソース、もしくはあらかじめ認可サーバーとの間で調整済の保護されたリソースに制限されている場合は、認可グラントとしてクライアントクレデンシャル (もしくは他のクライアント認証形式) が使用できる。
クライアントがクライアント自身の権限においてに行動している (つまりクライアントがリソースオーナーである) か、クライアントがあらかじめ認可サーバーとの間で調整済の保護されたリソースアクセスを求めている場合、クライアントクレデンシャルが認可グラントとして使用される。
リフレッシュトークンは発行すべきではないとされています。
f:id:acquapazza:20181220023601p:plain:w400

4.1 トークンエンドポイントへのリクエス

https://tools.ietf.org/html/rfc6749#section-4.4.2

POST {トークンエンドポイント} HTTP/1.1
Host: {認可サーバー}
Authorization: Basic {Basic認証パスワード} // クライアントパスワードを所有している場合
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials // 必須 client_credentials指定
&scope={スコープ群} // 任意

Basic認証の代わりにclient_id & client_secretを使用するのも可能。

4.2 トークンエンドポイントからのレスポンス

https://tools.ietf.org/html/rfc6749#section-4.4.3

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

{
    "access_token":{アクセストークン}, // 必須
    "token_type":{トークンタイプ}, // 必須
    "expires_in":{有効秒数}, // 任意
    "scope":{スコープ群} // トークンエンドポイントへのリクエストと差異がある場合は必須
}

5 リフレッシュトークンフロー(Refreshing an Access Token)

6. Refreshing an Access Tokenで定義されているフロー。
事前に発行を受けていたリフレッシュトークンをトークンエンドポイントに提示することで、アクセストークンの再発行を受ける。
リフレッシュトークンはアクセストークンを取得するために使用されるクレデンシャルである。
リフレッシュトークンは認可サーバーによってクライアントに対して発行され、現在のアクセストークンが無効化されたあるいは期限切れの際に新しいアクセストークンを取得するため、または同一あるいは狭い範囲で追加のアクセストークンを取得するために利用される (アクセストークンはリソースオーナーによって認可されるよりも有効期限は短く、権限が少なくてもよい)。
リフレッシュトークンの発行はオプションであり、認可サーバーの判断に委ねられる。
認可サーバーがリフレッシュトークンを発行する場合、アクセストークン発行の際にリフレッシュトークンも含まれる。
f:id:acquapazza:20181220023948p:plain:w400

5.1 トークンエンドポイントへのリクエス

https://tools.ietf.org/html/rfc6749#section-6

POST {トークンエンドポイント} HTTP/1.1
Host: {認可サーバー}
Authorization: Basic {Basic認証パスワード} // クライアントパスワードを所有している場合
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token // 必須 refresh_token指定
&refresh_token={リフレッシュトークン} // 必須
&scope={スコープ群} // 任意

Basic認証の代わりにclient_id & client_secretを使用するのも可能。

5.2 トークンエンドポイントからのレスポンス

https://tools.ietf.org/html/rfc6749#section-5.1

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

{
    "access_token":{アクセストークン}, // 必須
    "token_type":{トークンタイプ}, // 必須
    "expires_in":{有効秒数}, // 任意
    "refresh_token":{リフレッシュトークン}, // 任意
    "scope":{スコープ群} // トークンエンドポイントへのリクエストと差異がある場合は必須
}