こんにちは! 最近は熱燗にはまってます。 バックエンドエンジニアのりほやんです。
本記事では、最近2段階認証などにもよく使われているSMS認証のサーバーサイド実装についてご紹介します。 FacebookAccountKitを用いて実装しました。
SMS認証とは
SMS認証とは、SMS(ショートメッセージ)を利用した認証方法です。
ユーザーが入力した電話番号に対してショートメッセージを送り、ショートメッセージに記載された認証番号を入力することでユーザーを認証する方法です。
FacebookAccountKitとは
FacebookAccountKitはFacebookがSMS認証用に提供しているサービスです。
電話番号やメールアドレスを用いて、ユーザー認証を行うことができます。
Web, iOS, Androidの3種類のSDKが提供されています。
利用価格についてですが、2018年8月までは無料で使えるそうです。
2018年8月までSMSの課金は行いません。2018年9月以降、1か月あたり10万件を超えるSMSの確認メッセージには通常のSMS料金が課金される可能性があります。
https://developers.facebook.com/docs/accountkit/faq
認証の流れ
大まかな流れは下記のようになります。 参考: https://developers.facebook.com/docs/accountkit/overview
- アプリ内でユーザーが電話番号を入力
- Account Kitから、入力された電話番号にSMSが届く
- SMSに記載された確認番号をアプリに入力し認証
- 認証が完了すると、Account Kitからaccess_codeが発行される
- 発行されたaccess_codeをサーバーに送信
- アプリから送られたaccess_codeを元にaccess_tokenを発行
- access_tokenを用い、AccountKit Graph APIからユーザー情報を取得
この記事では、サーバーサイドの認証である、6と7の処理について説明します。
サーバーサイドの実装方法
以下の手順でSMS認証を行います。
- FacebookAccountKitの設定
- access_codeからaccess_tokenを取得
- access_tokenを用いてAccountKit Graph APIからユーザーの情報を取得
1. FacebookAccountKitの設定
初めにFacebookAccountKitの設定をします。 AccountKitを導入するためにはFacebookアプリケーションを作成している必要があります。
こちらからAccountKitを使いたいFacebookアプリケーションの画面に行き、 プロダクトの『製品を追加』をクリックし、AccountKitの設定をクリックします。
AccountKitの設定から、『サーバー認証をオンにしますか』を有効にし、スタートボタンを押します。
サーバー認証をオンにすると、設定画面において『App Secretをオンにする』が有効になります。
以上で、FacebookAccountKit側の設定は完了です。
2. access_codeからaccess_tokenを取得
サーバーでは、アプリからaccess_codeを受け取りますが、access_codeではユーザーの情報を取得することはできません。 access_codeを用いて、ユーザーの情報を取得できるaccess_tokenを取得する必要があります。
Facebook AccountKit Graph APIは2018年2月8日現在、バージョン1.3で下記のURLを用います。
https://graph.accountkit.com/v1.3/
accesss_tokenを取得するために、/access_token
というエントリポイントに対して下記パラメーターで、GETリクエストを送りaccess_tokenを取得します。
bodyパラメーター
{ grant_type: 'authorization_code', code: アプリから送られてきたaccess_code, access_token: アプリアクセストークン }
access_tokenについて
access_tokenは2種類存在します。 ユーザーアクセストークンとアプリアクセストークンです。 詳しくは、ドキュメントを参考にしてください。
ユーザーの情報を取得するために必要なのは、ユーザーアクセストークンです。 ユーザーアクセストークンを取得するために、ここではアプリアクセストークンをパラメーターに指定する必要があります。 アプリアクセストークンは、アプリIDとAccountKitAppSecretを連結したもので、下記のように記述します。
AA|アプリID|AccountKitAppSecret
アプリIDとAccountKitAppSecretは、FacebookアプリケーションのAccountKitのダッシュボードで確認できます。
レスポンス
リクエストが成功すると、以下のようなJSONが返ってきます。 JSON内のaccess_tokenを、ユーザーの情報を取得する際に使用します。
{ "id" : account_kitのユーザーID, "access_token" : ユーザーアクセストークン, "token_refresh_interval_sec" : トークンの利用期限 }
3. graph apiからユーザー情報を検証
取得したaccess_tokenを用いて、graph apiを叩きます。
/me
というエントリポイントに対して下記のパラメーターでGETリクエストを送り、ユーザーの情報を取得します。
bodyパラメーター
{ access_token: アプリアクセストークン, appsecret_proof: appsecret_token, }
appsecret_proofについて
AccounKitのダッシュボードにて『App Secretをオンにする』設定が有効にした場合、access_tokenを使用するリクエストにはappsecret_proofが必須になります。 appsecret_prooftとは、リクエストが自身のサーバーから行われたものであることを証明するためのパラメーターです。
appsecret_proofは、access_tokenのSHA-256ハッシュで、キーにAccountKitAppSecretを用います。
AccountKitの公式ドキュメントにはPHPでの記述例が下記のように紹介されています。
$appsecret_proof = hash_hmac('sha256', $access_token, $app_secret);
Ruby on Railsではappsecret_proofを求める場合はopensslを用い、以下のように書くことができます。
OpenSSL::HMAC.hexdigest('sha256', AccountKitAppSecret, ユーザーアクセストークン)
算出したappsecret_proofを、パラメーターとして使用します。
レスポンス
リクエストが成功すると、以下のようなJSONが返ってきます。
{ id: account_kitのユーザーID, phone: { number: 電話番号 country_prefix: 国番号, national_number: 国番号を除いた電話番号 }, application: { id: アプリID }
レスポンスに含まれるアプリIDを用い、正しいアプリIDと比較して不正なレスポンスではないことを確認します。 得られたユーザーの情報から、DBと照合しユーザーログインを行います。
注意点
access_codeの使用期限
access_codeは、1度しか使えません。 一度使用したaccess_codeを再度使用した場合400エラーが発生します。
Account_kitアカウントIDについて
Account_kitアカウントIDについて公式ドキュメントには、下記のように記述されています。
これらのアカウントIDは、アプリ固有のものです。アプリにFacebookログインも使用する場合、Facebookのapp-scoped IDと競合することはありません。 https://developers.facebook.com/docs/accountkit/overview?locale=ja_JP
しかし実際どのような場合にAccount_kitアカウントIDが変わるのかが詳しく記述されていないため使用する際は注意が必要です。 電話番号に対して固有の値なのか、デバイスなどが変われば変わる値なのかは実際に検証する必要があります。
まとめ
本記事では、FacebookAccountKitを用いたSMS認証についてご紹介しました。 FacebookAccountKitはとてもシンプルなため、簡単にSMS認証が導入できます。 特にFacebookログインを実装した経験があると、GraphAPIの叩き方などが共通しているためスムーズに取り入れることができると思います。 ぜひこの記事がSMS認証導入のきっかけになれば幸いです。
VASILYでは、新しいことに挑戦できるエンジニアを募集しています。 興味ある方は以下のリンクからご応募ください。