paiza開発日誌

IT/Webエンジニア向け総合求人・学習サービス「paiza」(https://paiza.jp ギノ株式会社)の開発者が開発の事、プログラミングネタ、ITエンジニアの転職などについて書いています。

2015年7月9日以降にFacebook認証でメールアドレスが取れない問題とその対策

f:id:paiza:20140712194904j:plainこんにちは、吉岡(@)です。

Facebook、LINE、TwitterなどのアカウントでログインするSNS連携認証は、簡単にログインできること、パスワード管理を一元化できることなどから多くのサービスで採用されています。

f:id:paiza:20150722161607p:plain

このSNS連携認証ですが、FacebookSNS認証の仕様が2015年7月9日にリリースされたGraph API v2.4により、仕様が変更されています。

Introducing Graph API v2.4 https://developers.facebook.com/blog/post/2015/07/08/graph-api-v2.4/

特にSNS認証に関連した部分として、デフォルトで取得できるユーザ情報がidとnameのみになり、それ以外については明示的に指定しない限り取得できなくなっています。

APIのバージョンはFacebookアプリケーションごとに別になっており、作成された時期によってバージョンが異なるようです。そのため、以前は動いていたコードが、APIキーを変えたら動かなくなった、という問題が発生します。

ここでは、この問題の概要と対応策について説明します。

Facebook APIの変更点

実際のAPIの動作については、Graph API Exploreを使うと確認できます。

https://developers.facebook.com/tools/explorer/145634995501895/?method=GET&path=me

API v2.3の場合は、E-mailアドレスなど多くの情報が取得できていました。

f:id:paiza:20150722160346p:plain

API v2.4では、デフォルトでは"name", "id"のみ取得できるようになっています。

f:id:paiza:20150722160359p:plain

fieldsパラメータで"me?fields=email"のように指定することでE-Mailアドレスも取得できます。主要な公開情報の取得は、"me?fields=..."のように指定できます。

f:id:paiza:20150722160537p:plain

また、User APIの詳細についてはこちらで確認いただけます。

Graph API Reference - User https://developers.facebook.com/docs/graph-api/reference/user

APIのサポート期間

現時点で、v2.3時代に作ったAPIはすぐには無効にはなりませんが、古いAPIについては、新しいAPIがリリース後2年で終了します。2年が経過した時点で、v2.3ベースのAPIについても強制的にv2.4ベースのAPI呼び出しとして扱われます。

APIのサポート期間は以下で確認できます。

Platform Versioning https://developers.facebook.com/docs/apps/versions

対応方法

FacebookSNS認証はJSONを用いたWeb APIとして実装されていますが、実際のアプリケーション開発では何らかのフレームワークを利用することが多いと思います。ここでは以下のような利用方法での対応を記載します。

APIの直接利用

APIを直接利用する場合、URLのパラメータで以下のようにフィールドを指定します。

https://graph.facebook.com/me?fields=id,email,gender,link,locale,name,timezone,updated_time,verified,last_name,first_name,middle_name

Facebook SDK(PHP, JavaScript, iOS, Android)での利用

Facebook SDKではAPIのエンドポイントでパラメータを指定します。

PHP

$request = new FacebookRequest(
  $session,
  'GET',
  '/me?fields=id,email,gender,link,locale,name,timezone,updated_time,verified,last_name,first_name,middle_name'
);

JavaScript

FB.api(
    "/me?fields=id,email,gender,link,locale,name,timezone,updated_time,verified,last_name,first_name,middle_name",
    function (response) {...}
);

iOS

FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
                               initWithGraphPath:@"/me?fields=id,email,gender,link,locale,name,timezone,updated_time,verified,last_name,first_name,middle_name"
                                      parameters:params
                                      HTTPMethod:@"GET"];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection,
                                      id result,
                                      NSError *error) {
  ...
}];

Android

new GraphRequest(
    AccessToken.getCurrentAccessToken(),
    "/me?fields=id,email,gender,link,locale,name,timezone,updated_time,verified,last_name,first_name,middle_name",
    null,
    HttpMethod.GET,
    new GraphRequest.Callback() {
        public void onCompleted(GraphResponse response) {
            /* handle the result */
        }
    }
).executeAsync();

Ruby on Rails(Omniauth)での利用

Omniauthでは、v2.1.0でデフォルトでname,emailフィールドが含まれるように対応予定となっています。Github上の最新コミットでは7月19日にmasterブランチに反映されています。それ以前のバージョンでは、以下のようにfieldsを指定します。

Devise.setup do |config|
  config.omniauth(:facebook, 'APIキー', 'SECRETキー',
    {:scope => 'email', :info_fields => 'id,email,gender,link,locale,name,timezone,updated_time,verified,last_name,first_name,middle_name'})
end

関連情報: Facebook OAuth2 Strategy for OmniAuth (Github) https://github.com/mkdynamic/omniauth-facebook

Fix default info_fields to 'name,email' #209 (Github) https://github.com/mkdynamic/omniauth-facebook/pull/209

Facebook OAuth is not returning email in user info (stackoverflow) http://stackoverflow.com/questions/31503090/facebook-oauth-is-not-returning-email-in-user-info/31554071#31554071

Node.js(Passport-facebook)での利用

Node.js用の認証ライブラリPassport-facebookを利用する場合、StrategyクラスのprofileFieldsで取得するフィールドを指定します。

  passport.use(new FacebookStrategy({
      clientID: config.facebook.clientID,
      clientSecret: config.facebook.clientSecret,
      callbackURL: config.facebook.callbackURL,
      profileFields: ['displayName', 'id', 'email', 'gender', 'link', 'locale', 'name', 'timezone', 'updated_time', 'verified'],
    },

なお、上記対策を行わなずにE-Mailアドレスを利用した場合、以下のようなエラーが発生します。

/app/server/auth/facebook/passport.js:21
                                 ^
            email: profile.emails[0].value,
TypeError: Cannot read property '0' of undefined

関連情報: passport-facebook https://github.com/jaredhanson/passport-facebook

Passport-Facebook not providing email even if it is in scope (stackoverflow) http://stackoverflow.com/questions/31279066/passport-facebook-not-providing-email-even-if-it-is-in-scope/31554393#31554393

まとめ

Facebook Graph API v2.4のリリースに伴う、Facebook認証でメールアドレスが取得できなくなる問題と、その対応方法について説明しました。新規に作成したFacebookアプリケーションについては、API v2.4しか利用できません。また、v2.3以前のAPIを既に作成して利用している場合は2年間は利用できますが、直前・直後であわてないように、また新しいフレームワーク等は最新のAPIを前提とすることになると思いますので早めに対応されることをお勧めします。




paizaではITエンジニアとしてのスキルレベル測定(9言語に対応)や、プログラミング問題による学習コンテンツ(paiza Learning)を提供(こちらは21言語に対応)しています。テストの結果によりS,A,B,C,D,Eの6段階でランクが分かります。自分のプログラミングスキルを客観的に知りたいという方は是非チャレンジしてみてください。

http://paiza.jp