OAuthとAPIキー、アクセスするデータの種類とAPIの認証方法の関係

Webアプリケーションに外部サービスを組み込む場合、Web API(以下、API)を通じてデータを取得する方法が一般的になってきました。

  • Google MAPのように、Webアプリケーション上に提供された地図データを表示する。
  • Twitterのように、表示しているページを簡単にツイートするボタンを設置する。
  • SlackやChatworkのようなチャットアプリケーションに自動投稿するボットアプリを作る。

これらの操作はすべて、APIと呼ばれるそれぞれのサービスが提供するインターフェイスを使って実現可能です。

どのサービスも、アカウントがあれば、利用するために必要なAPIキーなどの情報は簡単に取得できるので、利用しやすい環境が整ってきていますが、扱うデータの種類やアプリケーションの用途などによって、APIへのアクセスの仕方に違いがあります。

今回は、Twitter API、Google API、Chatwork APIの3つのAPIサービスのログインの仕方から、アクセスするデータと認証方法の関係を見ていきたいと思います。

Twitter APIの場合

まずはTwitter APIから触ってみます。

Twitter APIへのログイン方法には、いくつか種類がありますが、今回は、Application-only Authenticationという種類のものを試してみます。

この認証方法では、ユーザー情報の変更などは行えず、タイムラインの取得やユーザーのフォロワー情報の取得、ツイートの検索などができるようになります。
ユーザーデータの変更(例えば、ツイートをする、など)を行う場合は、必ずOAuth2によるユーザー認証が必要ですので、今回の手順では操作することはできません。

全ての操作を網羅するのは紙幅の関係上難しいですが、よく行う動作についてまとめてみました。

 Application-only AuthenticationUsing Oauth
特定のユーザーのユーザーのタイムライン取得
特定のユーザーのフォロワー情報の取得
ツイートの検索
ツイートの投稿
特定ユーザーの情報の取得
ダイレクトメッセージの取得

Twitter APIの場合は、アプリケーションに対して「コンシューマーキー(Consumer key)」と呼ばれるものと「シークレット(Secret)」と呼ばれるものが付与されます。
この2つを使って、ベアラートークン(Bearer token)を作り、認証にかけ、成功すればようやく、データにアクセスするためのアクセストークン(Access token)が取得できます。

ベアラートークンを作成する

ベアラートークンは、コンシューマーキーとシークレットの2つを所定の手順で別の文字列に変換したものです。

まず、2つの文字列をRFC1738の仕様に則って変換します。
PHPでは、rawurlencode()関数を通すことで、この処理を行います。

$consumer_key = rawurlencode('コンシューマーキー');
$secret = rawurlencode('シークレット');

続いて、URLエンコード済みの文字列を半角コロンで繋ぎ、一つの文字列にします。

$bearer_token = $consumer_key. ':' . $secret;

さらに、一つになった文字列をBase64形式に変換します。

$bearer_token = base64_encode($bearer_token);

こうしてできた文字列を、ベアラートークンと呼びます。

アクセストークンを取得する

ベアラートークンを作成したら、oauth2/token APIにアクセスし、アクセストークンを取得します。

  • HTTPヘッダーのAuthorizationフィールドに、「Basic 」 + ベアラートークンの値をセット。
  • 同じくHTTPヘッダーのContent-Typeフィールドに、「application/x-www-form-urlencoded;charset=UTF-8」をセット。
  • POSTデータに「grant_type=client_credentials」をセット。

以上の準備ができたら、アクセストークン取得用のAPIにアクセスします。

// アクセストークンを取得する
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.twitter.com/oauth2/token');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
  'Authorization: Basic '. $bearer_token,
  'Content-Type: application/x-www-form-urlencoded;charset=UTF-8',
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'grant_type=client_credentials');
$response = curl_exec($ch);

JSONデータが返ってくるので、「access_token」キーの値を取得。
errorsというキーが含まれている場合は、こちらのエラー集を頼りに修正していきます。

これでアクセストークンの取得ができました。

Google APIの場合

Google APIは、2017年12月現在、Google Cloud Platform(以下、GCP)に統合され、GCPのアカウントを使ってAPIを有効にする必要があります。
APIもGCP上のプロジェクト毎に有効化させる必要がありますので、APIを有効化する前に、プロジェクトを作成しておきます。

APIの有効化ができれば、続いて、認証に関する設定を行います。

Google APIには、3つの認証方法が用意されています。

認証方法説明
APIキープロジェクト毎に払い出されるAPIキーを使って、APIにアクセスする。
OAuthクライアントIDOAuth認証を通じて、ユーザーに対して、ユーザーデータへのアクセス権をリクエストし、同意を得る。
サービスアカウントキーロボットアカウントによるサーバー間のアクセス認証を行う。

ユーザーデータにアクセスして情報を変更したりする場合(Google Driveにファイルを保存するなど)、OAuthを使った認証が必要になります。
ここでは、Google Maps Geocoding APIを使って、郵便番号から住所の一部を取得する場合のサーバーとGCPのAPIサーバー間のやりとりで利用する認証を想定した手続きについて考えてみます。

サーバーとAPIサーバー間の通信は、APIキー、もしくはサービスアカウントキーが利用できますが、手軽なのは、APIキー方式です。

APIキーはGCPのAPIメニューにある認証情報から作成できます。
重要な点として、APIキー方式の場合、APIキーを知っていれば、誰でもあなたのアカウントを利用してGoogle APIを利用できてしまうので、なんらかの制限を加える必要があるということです。

制限項目として設定できるのは、以下の4つです。

  • HTTPリファラー
  • IPアドレス
  • Androidアプリ
  • iOSアプリ

サーバーで使う場合は、IPアドレスが一意になっていることがほとんどですので、IPアドレスを利用するのが良いかと思います。
APIキーはアプリでも使うことができますが、Androidの場合は、アプリのパッケージ名とフィンガープリントを登録して、利用できるアプリを制限します。
iOSアプリの場合は、アプリのバンドルIDを登録するだけです。

https://maps.googleapis.com/maps/api/geocode/json?address=556-0021&key=[APIキー]

上記のURLの「key=」の後に適切なAPIキーを埋め込めば、ブラウザからでもAPI実行できるくらいお手軽です。
仮にAPIキーが漏れてしまうと、アカウントの設定によっては、想定外の請求がきてしまうおそれもありますので、制限は必ず設定しておくことをおすすめします。

Chatwork APIの場合

Chatwork APIは、オープンβではありますが、ユーザーごとにAPIキーを払い出す機能があります。

このAPIキーを使えば、APIキーが紐付けられたユーザーデータ全てにアクセスできるため、少しTwitterやGoogleのAPIとはアクセスできるユーザーデータに違いがあります。

Slackもそうですが、チャットの場合、ボットを作ったり、自動返信やChatworkからSlackへメッセージを集約する、またはその逆など、コミュニケーションにおけるインフラのような使い方をするケースが多いため、OAuthのような認証をいちいち通す必要があると、利用しにくいという側面もあります。

ChatworkにもOAuthによる認証を使った仕組みはあります。
ただ、筆者は業務上でChatworkを利用していることもあって、基本的には自分のアカウントやボットアカウントのAPIキーを使って処理をするケースばかりですが、今のところ不都合はありません。

Chatwork APIにアクセスするのは非常に簡単で、HTTPヘッダーにX-ChatWorkTokenフィールドを追加し、APIキーを値にセットするだけです。
ちなみに、Chatworkでは、APIキーのことをAPIトークンと呼んでいますが、他のサービスと担う役割が同じなので、APIキーとして話を進めていきます。

PHPでは、cURLを使って書く場合、curl_setopt()関数を使って、色々設定する必要があります。

// チャットルームの一覧を取得する
$key = 'APIキー';
$ch = curl_init('https://api.chatwork.com/v2/rooms');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
  'X-ChatWorkToken: '. $key,
]);
$response = curl_exec($ch);

Linuxのコンソールなら、curlコマンドを使うと、1行で済みます。
APIが返すJSONデータを確認したい場合などは、curlコマンドを使うと手軽にレスポンスを確認でき、jqコマンドにパイプすれば、コマンドだけでJSONデータの加工まで完結できてしまうので、シェルスクリプトにも組み込みやすい利点があります。

# APIを実行する
curl -H "X-ChatWorkToken: APIキー" "https://api.chatwork.com/v2/rooms"

最近では、Windows 10環境でも「Windows Subsystem for Linux」からcurlコマンドが実行できるので、OSを問わず利用できるようになりました。

まとめ

今回は、APIにアクセスするために必要な認証の部分に焦点を当てて、TwitterとGoogleというメジャーなAPIサービスと、Chatworkという少し毛色の違うサービスの認証を見てみました。
払い出されるAPIキーの有効範囲について比較してみると、以下のようになります。

サービス名APIの有効範囲備考
Twitterアプリケーション 
GoogleGCPのプロジェクト各プロジェクト毎に利用するAPIを有効化する
Chatworkユーザーアカウント 

Twitter APIとGoogle APIでは、どちらのAPIもアクセスするデータの種類によって、認証形態が違うことがわかりました。
また、サービスの性質によっては、認証手続きが利用を阻害するおそれもあることもわかりました。

APIが提供する処理や扱うデータに着目すると、扱う情報によって認証の仕組みが異なり、大きく分けると、APIによってアクセスできるデータは公開されているパブリックなデータと、ユーザー固有のユーザーデータに分類できます。

ツイートの取得や地図情報の取得といったパブリックデータへのアクセスには、固有のAPIキーがあればよく、ユーザーデータにアクセスする場合は、OAuthを使ったユーザーの認可というプロセスを経てからでなければアクセスできない、ということになっています。

この考え方は非常に重要で、APIサービスを作る場合も、認証はほぼ必須の項目ですので、APIがアクセスするデータを意識しながら、認証の仕組みを整えることが大切です。