GitHubで認証するサービスを作る機会があったのでまとめておきます。 ゴールはユーザーのプロフィールを取得するまでで、CakePHPで実装したので他の環境の人はいい感じに置き換えてください。

アプリケーションを作成する

まずはこちらのURLからアプリケーションを作成しましょう。

アプリケーションを作成すると下図のような画面になると思います。右上の”Client ID”と”Client Secret”は後で使います。

image

codeを取得する

次にcodeを取得します。codeはClient ID,Client Secretと合わせてacsess tokenを取得するのに用います。

まずはGitHubのパーミッション取得ページにアクセスしましょう。URLは

https://github.com/login/oauth/authorize?scope=user,email&client_id=YOURCLIENTID

のようになっており、getパラメータのscopeが取得するパーミッションの種類、client_idが認証するアプリケーションのclient idです。 今回はuserとemailをscopeにしました。

scopeの種類はGitHubのサイトに一覧であります。

パーミッションを許可するとアプリケーションを作成する時に設定した”Authorization callback URL”戻ってきます。

Authorization callback URLがhttp://hoge.com/github/callbackなら、ユーザーがパーミッションの承認をした後に

http://hoge.com/github/callback?code=YOURCODE

のようにGetパラメータとしてcodeが渡されます。 それを下記のように取得します。

<?php
$code = $this->request->query['code'];

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

アクセストークンは取得したcode,Client ID,Client Secretを

https://github.com/login/oauth/access_token

のURLにPOSTして取得します。CakePHPで書くと

<?php
$data = array(
    'client_id' => YOUR_CLIENT_ID,
    'client_secret' => YOUR_CLIENT_SECRET,
    'code' => $code,
);
App::uses('HttpSocket', 'Network/Http');
$http_socket = new HttpSocket();
$url = 'https://github.com/login/oauth/access_token';
$request = array(
    'header' => array('Content-Type' => 'application/json')
);
$data = json_encode($data);
$result = $http_socket->post($url, $data, $request);
$response = json_decode($result->body, true);
$access_token = $response['access_token'];

このように取得できます。

プロフィールを取得する

今回はscopeをuserとemailにしましたが、userとemailのパーミッションを取得しても1つのAPIで一度に取得することは出来ません。 Facebookのreadパーミッションとpublishパーミッションが一度に取得出来ないのに似てますね。

URLはuserが

https://api.github.com/user

emailが

https://api.github.com/user/emails

で、それぞれGetで取得します。

<?php
// プロフィールを取得する
$data = array(
    'access_token' => $access_token,
);
$url = 'https://api.github.com/user';
$request = array(
    'header' => array('Content-Type' => 'application/json')
);
App::uses('HttpSocket', 'Network/Http');
$http_socket = new HttpSocket();
$result = $http_socket->get($url, $data, $request);
$profile = json_decode($result->body, true);

// プライマリなemailアドレスをprofileに追加する
$data = array(
    'access_token' => $access_token,
);
$url = 'https://api.github.com/user/emails';
$request = array(
    'header' => array('Content-Type' => 'application/json')
);
App::uses('HttpSocket', 'Network/Http');
$http_socket = new HttpSocket();
$result = $http_socket->get($url, $data, $request);
$response = json_decode($result->body, true);
$email = Hash::extract($response, '{n}[primary=true]');
$email = $email[0];
$profile['email'] = $email['email'];

これでメールアドレスの情報が含まれたプロフィールを取得することが出来ました。 GitHubは複数のemailを登録することができ、その中でプライマリなメールアドレスを設定するのでemailのAPIはメールアドレスが複数含まれた配列になって返ってきます。 今回はプライマリなメールアドレスだけどプロフィールに追加しました。

注意点

以上で終了ですが、code, アクセストークンの扱いについて注意する必要があります。

codeはワンタイム

codeは取得して一度アクセストークンの取得に用いると破棄され、使用できなくなります。 そのため、もう一度アクセストークンを取得する時は再びパーミッション取得のページに行ってcodeを取得する必要があります。

codeが変わってもアクセストークンは変わらない

上記のように再度codeを取得し、アクセストークンを取得しても以前のアクセストークンと同じ値が返ってきます。

ただし、scopeを変更するとアクセストークンは変わる

今回はuserとemailのscopeでしたが、これにrepoなどのscopoを追加してcodeを取得した場合はアクセストークンが変わります。

上記3つの点は僕がAPIを叩いたりして気付いたことなので厳密には違うかもしれないので詳しくは公式のドキュメントを読んで下さいm(_ _)m

参考

Basics of Authentication | GitHub API