Socialiteを使ってLaravelでTwitterログイン機能を実装


環境

  • PHP 7.2.18
  • Laravel Framework 5.5.45
  • Socialite 3.3

はじめに

今回は、LaravelでSNSログインする際にめんどくさいことを色々やってくれるライブラリのSocialiteを使って、Twitterログインを実装した時の話を書きます。
※かなり前(投稿から約4ヶ月前)に詰まった話なので、記憶は曖昧ですが書き記します。

まずはTwitter Developersからアプリの作成

Twitterログイン機能を作るには、まず今回の実装用にTwitter側でアプリを立てておかなければなりません。
そのアプリを作成するためには、以下のサイトにログインしてアプリを新規作成してください。
Twitter Developers

アカウントやアプリの細かい作成や設定方法は、こちらのサイトで詳しく説明されているのでそちらをご参照ください。

Socialiteのインストールと設定

Socialiteってなんぞ…?

現在、SNSログインを実装しようとする際、基本的に認証認可はOAuthかOpenIdConnectというプロトコルを利用します。これは、安全面を加味した堅固なプロトコルだからです。このプロトコルを利用して認証認可の実装を行うには、少々複雑な実装をしなくてはなりません。でも、昨今のwebサービスでは欠かせないのがSNSログイン。そこで、Laravelではその実装のお手伝いをしてくれるライブラリが存在していて、それがSocialiteというわけです!

インストール

$ composer require laravel/socialite

config/app.php の設定

Socialiteを利用するためにサービスプロバイダへの追加とaliasをはっておきます。

  • サービスプロバイダへの追加
config/app.php
'providers' => [
.
.
/**
* Socialite
*/
Laravel\Socialite\SocialiteServiceProvider::class,
.
.
],
  • aliasをはる
config/app.php
'aliases' => [
.
.
'Socialite' => Laravel\Socialite\Facades\Socialite::class,
.
.
],

client_idclient_secret の設定

OAuthやOpenIdConnectに必要な、client_idclient_secretを設定

config/services.php
return[
.
.
    /**
     * socialite Settings
     */
    'twitter' => [
        'client_id'     => env('TWITTER_API_KEY'),
        'client_secret' => env('TWITTER_API_SECRET'),
        'redirect'      => env('TWITTER_CALLBACKURL'),
    ],
.
.
]
.env
# Twitter
TWITTER_API_KEY= Twitter Developers で作成したアプリのAPI key
TWITTER_API_SECRET= Twitter Developers で作成したアプリのAPI secret key
TWITTER_CALLBACKURL= Twitterから戻ってくる際に叩いて欲しいURL(Twitter Developersにも設定する必要あり)
TWITTER_ACCESS_TOKEN= Twitter Developers で作成したアプリのAccess token
TWITTER_ACCESS_TOKEN_SECRET= Twitter Developers で作成したアプリのAccess token secret

これでSocialiteの準備は一旦完了!

Twitter認証認可処理の実装

今回は面倒臭いので「ログイン処理」は割愛して「認証認可」までをします。
※ユーザー情報引っ張ってくるくらいまで
順を追って処理を書いていきます。
今回の処理フローを超簡単な図にするとこんな感じ↓

1.Socialiteのドライバーにリダイレクトさせる

SnsBaseController.php
<?php

namespace App\Http\Controllers;

use Socialite;

class SnsBaseController extends Controller
{
  // 1. Socialiteのドライバーにリダイレクトさせる
  public function getAuth($provider) {
    return Socialite::driver($provider)->redirect();
  }
}

2.Twitterから戻ってくる際のエンドポイント作成

SnsBaseController.php
<?php

namespace App\Http\Controllers;

use Socialite;

class SnsBaseController extends Controller
{
  // 1. Socialiteのドライバーにリダイレクトさせる
  public function getAuth($provider) {
    return Socialite::driver($provider)->redirect();
  }

  // 2. Twitterから戻ってくる際のエンドポイント作成
  public function authCallback($provider) {

  }
}

3.ユーザー情報の取得(ここでめちゃくちゃ詰んだ!)

SnsBaseController.php
<?php

namespace App\Http\Controllers;

use Socialite;

class SnsBaseController extends Controller
{
  // 1. Socialiteのドライバーにリダイレクトさせる
  public function getAuth($provider) {
    return Socialite::driver($provider)->redirect();
  }

  // 2. Twitterから戻ってくる際のエンドポイント作成
  public function authCallback($provider) {
    // 3. ユーザー情報の取得(ここでめちゃくちゃ詰んだ!)
    $user_info = $this->getProviderUserInfo($provider);
    dd($user_info); //デバック用
  }

  // 3. ユーザー情報の取得(ここでめちゃくちゃ詰んだ!)
  private function getProviderUserInfo($provider){
    switch ($provider) {
        case 'twitter':
            return Socialite::driver($provider)->user();
        default:
            return null
    }
  }
}

4.ルーティング設定

web.php
//Twitter
Route::get('sns/{provider}/login', 'SnsBaseController@getAuth');
Route::get('sns/{provider}/callback', 'SnsBaseController@authCallback');

今回詰んだ部分の話

前章の3番目の「ユーザー情報の取得」部分の処理で大きく詰まりました(1週間ほど)

エラー箇所

Socialite::driver($provider)->user();

色んなサイトをみても、この実装で書かれているのがほとんでした。
この処理で実装して動かしてみても、「セッションが引き継げてない」みたいなエラーしか返してくれませんでした。(以下、エラー)

Type error: Argument 1 passed to League\OAuth1\Client\Server\Server::getTokenCredentials() must be an instance of League\OAuth1\Client\Credentials\TemporaryCredentials, null given, called in /vendor/laravel/socialite/src/One/AbstractProvider.php on line 113

oauth.tempが取得できないというエラーでした

「一連の処理のどこかでhttp通信とhttps通信が混合しているのか?」とか、「自分のCentOSのネットワーク設定が悪さしているのか?」とか色々考えていたんですが、どれも関係なく途方にくれました。
Twitterではなくて、googleの情報を引っ張ってくる際は、

Socialite::driver($provider)->stateless()->user();

のように、stateless()メソッドを間に挟めばセッションの引き継ぎを行なってくれるらしいのですが、Twitterだとこのメソッド自体存在しないらしくundefined methodが出てしまいました。

いろいろ試した結果下記コードに修正すると動きました。

Socialite::driver($provider)->userFromTokenAndSecret(env('TWITTER_ACCESS_TOKEN'), env('TWITTER_ACCESS_TOKEN_SECRET'));

この書き方は、access_tokenとaccess_token_secretを取得できている際に直接指定して情報取得するやり方です。
ただ、現在ではどちらの書き方でも動いているので、何が原因だったのか未だにわからずです。。。

結論

このような困難を経て最終的にTWITTER_ACCESS_TOKENTWITTER_ACCESS_TOKEN_SECRETを使ったユーザー情報取得方法にたどり着いたわけですが、
最終的に何が問題だったのかわからないまま何処かのタイミングで上記エラーが解消されました。。。

各SNSで使うメソッドが違ったり古い情報に左右されたりなど、ライブラリ頼りでは混乱が多いですね。。。(現に1週間詰まった)
特にSNS周りだと、各々のSNSのバージョンアップだったり仕様変更だったりが割と早めなのでライブラリもそれに対応していくのが大変で昔の書き方だと動かないとかが多いんでしょうね…

今後はSNSログイン周りをライブラリに任せないで自分で実装しようと思いました。頭では処理フローを理解できているつもりですが、色々複雑なので次なる挑戦として頑張りたいと思います!