「クライアントタイプ」と「認可情報の有無」の2軸で有名APIを分類して調べてみた 

この記事は
「[DeNA IPプラットフォーム事業部 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/ippf)」
23日目の記事です。

#自己紹介
私は[MyAnimeList](https://myanimelist.net/)というアニメ・マンガのコミュニティープラットフォームサービスのサーバーサイドエンジニアをしている @kawabex です。


# tl;dr
ネット上で公開されているAPIについて、

 - 取得できる情報がユーザの認可が必要な情報かどうか
 - API呼び出し側のクライアントタイプ

の2軸で分類した際に、有名なAPI提供サービスはそれぞれの場合にどのような形式でAPIを提供しているのかを調べました。
# APIの分類


取得したいデータの種類とAPIを呼ぶクライアントのタイプで分類してマトリックスを作ると、

|        |    public client    |  confidential client      |
|:-----------------:|:------------------:|:------------------:|
| **public data**           |              ① |        ②        |
| **private data**           |            ③ |       ④       |

このようになり、4種類のパターンが考えられます。それぞれの単語の定義は後で説明します。


APIを提供している有名なサービスが、この①~④の4パターンについてどのような形式で（もしくはどのような技術を使って）APIを提供しているのか、まとめてみました。

以下にまとめた情報は2017/12/23現在のものです。
個人で調べた情報をまとめたので、もし間違っている部分があったら、教えていただけると幸いです。

この記事は随時追加・更新していきたいと思っています。

# 前提
## [OAuth2.0](https://tools.ietf.org/html/rfc6749)
ユーザの認可に基づいて安全にAPIをアプリに利用可能とするための標準仕様で、現在様々なAPIで広く用いられています。
OAuth2.0([Resource Owner Password Credentials Grant](https://tools.ietf.org/html/rfc6749#section-1.3.3) 以外)を利用すると、APIを呼ぶアプリ側にパスワードを含む認証情報が渡ってしまうことを回避できます。

この仕様についてはこれまで数多くの記事やブログで詳細な解説がされてきたので、この記事では説明しません。以下の記事を参考にして下さい。

 - [一番分かりやすい OAuth の説明 - Qiita](https://qiita.com/TakahikoKawasaki/items/e37caf50776e00e733be)
 - [OAuth 2.0 全フローの図解と動画 - Qiita] (https://qiita.com/TakahikoKawasaki/items/200951e5b5929f840a1f)
 - [RFC 6749 The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749)
 - [RFC 6749 の日本語訳] (https://openid-foundation-japan.github.io/rfc6749.ja.html)

## client type
APIを呼ぶクライアントのタイプを[RFC6749 section2.1](https://tools.ietf.org/html/rfc6749#section-2.1)に則って分類しました。

- **public client**
クライアントクレデンシャルの機密性を維持することができず, かつ他の手段を使用したセキュアなクライアント認証もできないクライアント
例: iOS, Androidなどのネイテイブアプリ、デバイス上のUserAgent (例えばWebブラウザ) 上で実行されるアプリ

- **confidential client**
クライアントクレデンシャルの機密性を維持できるクライアント
例：Webアプリ



## data type
本記事では、APIで提供している情報を個人のユーザーに関わる情報かどうかで2種類に分類しました。

- **public data**
ユーザ個人に関わる情報が含まれていない、誰でも取得できる公開情報。ユーザの認可が必要ではないデータ。


- **private data**
ユーザ個人に関わる情報が含まれているデータ。ユーザの認可が必要なデータ。



# 各サービスが提供しているAPIごとの情報

## [Google](https://developers.google.com/identity/protocols/OAuth2)
|        |    public client    |  confidential client      |
|:-----------------:|:------------------:|:------------------:|
| **public data**           |              OAuth 2.0 or API key |        OAuth 2.0 or API key        |
| **private data**           |            OAuth 2.0 Authorization Code Grant or Implicit Grant  |       OAuth 2.0 Authorization Code Grant       |

※Googleが提供するAPIの数は膨大なので、今回の分類に当てはまらない例外がある可能性があります。
### ① public data × public client
Googleはpublic dataをOAuthを使わずに簡単に取得できるようにするために、[API key という識別子を導入しています。](https://support.google.com/googleapi/answer/6158862)
すなわち、Googleは各クライアントが持つユニークな識別子として、OAuth2.0 IDとAPI keyの2種類を提供していることになります。
参考：[Credentials, access, security, and identity - Google API Console Help](https://support.google.com/googleapi/answer/6158857)

例1: [Google Sheets API Authorize Requests](https://developers.google.com/sheets/api/guides/authorizing)
例2: [Google Maps API Get API Key](https://developers.google.com/maps/documentation/directions/get-api-key)

### ② public data × confidential client
①に同じ。
調べた限り、public dataの提供方法に関しては、client type の違いによる差異は無いようです。
### ③ private data × public client
- UserAgentアプリ(例: webブラウザ上で動くJavaScriptアプリ)の場合  
[Implicit Grant](https://tools.ietf.org/html/rfc6749#section-4.2)を採用しています。  
https://developers.google.com/identity/protocols/OAuth2UserAgent
- Nativeアプリの場合(例: Android, Chrome, iOSアプリ)  
[Authorization Code Grant](https://tools.ietf.org/html/rfc6749#section-4.1)を採用しています。  
https://developers.google.com/identity/protocols/OAuth2InstalledApp

### ④ private data × confidential client
[Authorization Code Grant](https://tools.ietf.org/html/rfc6749#section-4.1)を採用しています。
https://developers.google.com/identity/protocols/OAuth2WebServer



## [Twitter](https://developer.twitter.com/en/docs/basics/authentication/overview/oauth)
|        |    public client    |  confidential client      |
|:-----------------:|:------------------:|:------------------:|
| **public data**           |              OAuth 2.0 Client Credentials Grant |        OAuth 2.0 Client Credentials Grant        |
| **private data**           |  OAuth 1.0a            |  OAuth 1.0a            |

### ① public data × public client
[OAuth 1.0a](https://oauth.net/core/1.0a/)を利用しているTwitterですが、public dataを取得するためのAPIのみ、[OAuth 2.0 Client Credential Grant](https://tools.ietf.org/html/rfc6749#section-4.4)を採用しています。
https://developer.twitter.com/en/docs/basics/authentication/overview/application-only

[RFC6749の仕様によると](https://tools.ietf.org/html/rfc6749#section-4.4)、

> The client credentials grant type MUST only be used by confidential clients.

と記載されているので、このパターンはRFC6749からは外れていることになります。これは、Twitterが基本的にOAuth1.0aを採用していることもあり、利便性を考えた結果だと思われます。

### ② public data × confidential client
[OAuth 2.0 Client Credential Grant](https://tools.ietf.org/html/rfc6749#section-4.4)を採用しています。


### ③ private data × public client
Twitter は他の主要なサービスとは違い、[OAuth 1.0a](https://oauth.net/core/1.0a/)を利用しています。
https://developer.twitter.com/en/docs/basics/authentication/overview/oauth
### ④ private data × confidential client
クライアントタイプによって違いは無く、③と同じです。



## Facebook
調査中

## [Reddit](https://github.com/reddit/reddit/wiki)


|        |    public client    |  confidential client      |
|:-----------------:|:------------------:|:------------------:|
| **public data**           |             OAuth 2.0 Custom Grant |        OAuth 2.0 Client Credentials Grant       |
| **private data**           |     OAuth 2.0 Implicit Grant        |       OAuth 2.0 Authorization Code Grant       |

### ① public data × public client
この組み合わせの為に、
> `grant_type=https://oauth.reddit.com/grants/installed_client`

という[OAuth 2.0 Extension grants](https://tools.ietf.org/html/rfc6749#section-4.5)に則ったカスタムグラントを提供しています。
https://github.com/reddit/reddit/wiki/OAuth2#application-only-oauth

このカスタムグラントにより、OAuth2.0の枠組みの中で出来る限りのクライアント特定を行った上で公開情報を提供しています。


### ② public data × confidential client
[Client Credential Grant](https://tools.ietf.org/html/rfc6749#section-4.4)を採用しています。
https://github.com/reddit/reddit/wiki/OAuth2#application-only-oauth
### ③ private data × public client
[Implicit Grant](https://tools.ietf.org/html/rfc6749#section-4.2)を採用しています。
https://github.com/reddit/reddit/wiki/OAuth2#authorization-implicit-grant-flow

### ④ private data × confidential client
[Authorization Code Grant](https://tools.ietf.org/html/rfc6749#section-4.1)を採用しています。
https://github.com/reddit/reddit/wiki/OAuth2#token-retrieval-code-flow

## [GitHub](https://developer.github.com/v3/)

|        |    public client    |  confidential client      |
|:-----------------:|:------------------:|:------------------:|
| **public data**           |              特に制限なし |        特に制限なし        |
| **private data**           |           OAuth 2.0 Authorization Code Grant or  カスタムフロー  |       OAuth 2.0 Authorization Code Grant       |

### ① public data × public client
クライアント単位での制限はかけていないようです。
https://developer.github.com/v3/guides/getting-started/#authentication
IP単位でのレートリミットは存在するようです。
### ② public data × confidential client
①に同じです。
### ③ private data × public client
 - [クライアント認証をGitHubで行う(ex. GitHubアカウントでログイン)3rd party アプリの場合](https://developer.github.com/v3/auth/#other-authentication-methods)  

>Third party applications that rely on GitHub for authentication should not ask for or collect GitHub credentials. Instead, they should use the [OAuth web flow](https://developer.github.com/apps/building-oauth-apps/authorization-options-for-oauth-apps/#web-application-flow).  

と記載されているように、[OAuth web flow](https://developer.github.com/apps/building-oauth-apps/authorization-options-for-oauth-apps/#web-application-flow)を利用することが推奨されています。GitHubは[Implicit Grant flow](https://tools.ietf.org/html/rfc6749#section-4.2)を提供していないので、結果的に[Authorization Code Grant](https://tools.ietf.org/html/rfc6749#section-4.1)フローの利用が推奨されてることになります。 

 - その他の場合  
ユーザ名とパスワード（もしくはユーザ名と[personal access token](https://github.com/blog/1509-personal-api-tokens)）のbasic認証により取得したアクセストークンを用いるフローが提供されています。  
https://developer.github.com/apps/building-oauth-apps/authorization-options-for-oauth-apps/#non-web-application-flow  
このフローは[OAuth 2.0 Extension grants](https://tools.ietf.org/html/rfc6749#section-4.5)には則っていないGitHub独自のフローです。

### ④ private data × confidential client
[Authorization Code Grant](https://tools.ietf.org/html/rfc6749#section-4.1)を採用しています。
https://developer.github.com/apps/building-oauth-apps/authorization-options-for-oauth-apps/#web-application-flow


## [Instagram](https://www.instagram.com/developer/)
|        |    public client    |  confidential client      |
|:-----------------:|:------------------:|:------------------:|
| **public data**           |              \- |        \-        |
| **private data**           |            OAuth 2.0 Implicit Grant |       OAuth 2.0 Authorization Code Grant       |

### ① public data × public client
ユーザーの認可が必要ない情報を取得するAPIは提供していません。

> The Instagram API requires an access_token from authenticated users for each endpoint. We no longer support making requests using just the client_id.

https://www.instagram.com/developer/endpoints/

### ② public data × confidential client
①に同じです。
### ③ private data × public client
[Implicit Grant](https://tools.ietf.org/html/rfc6749#section-4.2)を採用しています。
https://www.instagram.com/developer/authentication/
"Client-Side (Implicit) Authentication"の章
### ④ private data × confidential client
[Authorization Code Grant](https://tools.ietf.org/html/rfc6749#section-4.1)を採用しています。
https://www.instagram.com/developer/authentication/
"Server-side (Explicit) Flow"の章

# まとめ
想像以上に各サービスのAPI提供方法が異なっている印象を持ちました。ネイティブアプリ（今回の分類で言うと public client）の開発が盛んになってきた今、特に認証・認可周りはprivate clientへのAPI提供も強く意識しながらAPIを作っていく必要があると思いました。

明日24日は@m2mtu さんがGraphQLについて話してくれます。お楽しみに！