Laravel Socialiteを利用することでTwitter, GitHubなどのサービスを利用したOAuthでの認証機能の実装を簡単に行うことができます。本文書では実装方法を確認した後、実際にどのような処理が行われているか理解するためにコードを使って説明を行っています。

Laravel SocialiteでサポートしているOAuthのProviderではFacebook, Twitter, LinkdIn, Google, GitHub, GitLabです。本文書ではGitHubを利用して動作確認を行っています。それぞれのProviderのOAuthを利用するためにはアカウントを事前に持っている必要があります。GitHubのアカウントを持っていない人がいれば事前に取得しておいてください。

Laravel環境の構築

動作確認を行うためのLaravel環境の構築を行います。プロジェクトの作成後、GitHubから取得したユーザ情報を保存するデータベースとEmail/Passwordによる認証機能を実装することができるBreezeのインストールを行います。

Laravelプロジェクトの作成

laravel newコマンドを利用してLaravelプロジェクトの作成を行います。プロジェクト名には任意の名前をつけることができるのでここではlaravel10_socialiteとしています。


 % laravel new laravel10-socialite

プロジェクトの作成後laravel10_socialiteフォルダが作成されるので移動します。


 % cd laravel10_socialite

データベースの作成

各種Provider(ここではGitHub)での認証が完了するとユーザ情報が戻されるためそのユーザ情報をデータベースに保存するためデータベースが必要となります。

データベースには簡易に利用できるSQLiteデータベースを利用します。touchコマンドでdatabaseフォルダにdatabase.sqliteファイルを作成します。


 % touch database/database.sqlite

LaravelではデフォルトではMySQLのデータベースを利用するように設定されているのでSQLiteに変更するため.envファイルを更新します。.envファイルの中の先頭にDB_がついている環境変数の中からDB_CONNECTIONの値をmysqlからsqliteに変更します。それ以外DB_がついている環境変数は削除します。


DB_CONNECTION=sqlite

Laravel Breezeのインストール

Laravel Breezeをインストールすることでログイン画面などEmail/Passwordを利用した認証機能を簡単に実装することができます。Laravel SocialiteでEmail/Passwordの認証機能を利用するわけではありませんがログイン画面や認証後にリダイレクトされるダッシュボード画面などを利用することができます。

Email/Passwordによる認証とLaravel Socialiteによる認証はどちらか一つしか利用できないというわけではなく同時に利用可能です。Laravel Socialiteで認証した後はEmail/Passwordと同様の方法でログイン情報の管理を行います。
fukidashi

composerコマンドでLaravel Breezeのパッケージをインストールします。


composer require laravel/breeze --dev

パッケージのインストールphp artisan breeze:installコマンドでBreezeのインストールを行います。コマンドを実行するとどのスタックを利用するか聞かれますがここではbladeを選択します。選択するStackによってログイン画面などを構成するコードが変わります。ダークモードのサポートやPHPUnitの代わりにPestをインストールするか聞かれますがここでは”No”を選択します。JavaScriptパッケージのインストールとビルドも同時に行われます。bladeを選択しているにも関わらずJavaScriptやビルドが実行されるため?の人もいると思います。Bladeでもユーザとのインタラクティブな必要な箇所にAlpine.jsを利用しています。スタイルに利用しているTailwind CSSもビルドを利用します。


 % php artisan breeze:install

  Which stack would you like to install?
  blade ........ 0  
  react ........ 1  
  vue   ........ 2  
  api   ........ 3 
  Would you like to install dark mode support? (yes/no) [no]
❯ 

  Would you prefer Pest tests instead of PHPUnit? (yes/no) [no]
❯ 

   INFO  Installing and building Node dependencies.  


added 93 packages, and audited 94 packages in 8s

20 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

> build
> vite build

vite v4.1.4 building for production...
✓ 47 modules transformed.
public/build/manifest.json             0.26 kB
public/build/assets/app-cc5c6062.css  29.50 kB │ gzip:  5.76 kB
public/build/assets/app-9f9c98ef.js   69.59 kB │ gzip: 25.91 kB

   INFO  Breeze scaffolding installed successfully.  

Breezeのインストール完了後、php artisan serveコマンドを実行して開発サーバを起動します。


% php artisan serve

   INFO  Server running on [http://127.0.0.1:8000].  

  Press Ctrl+C to stop the server

Laravelの初期ページが表示されます。Laravel Breezeをインストールしたので画面右上には”Log in”と”Register”のリンクが表示されます。

Laravelのトップページ
Laravelのトップページ

Laravel Socialiteのインストール

composerコマンドでLaravel Socialiteパッケージのインストールを行います。


 % composer require laravel/socialite

GitHubの設定

OAuth ProviderとしてGitHubを利用しますがそのためにはGitHubのアカウントを持っている必要があります。GitHubアカウントを利用してOAuthで利用するClient IDとClientn Secretsの取得とcallback URLの設定を行う必要があります。callback URLはGitHubで認証が完了した後にGitHubから情報(Code)をもらうために利用します。

GitHubにログイン後、ヘッダーの右上にあるアイコンをクリックして”Setting”を選択します。

メニューからSettingを選択
メニューからSettingを選択

Setting画面の左側のメニューの最下部にある”Developer settings”をクリックします。

Developer settingsの選択
Developer settingsの選択

Developer settingsの画面の左メニューから”OAuth App”を選択します。

OAuth Appsの選択
OAuth Appsの選択

OAuth applicationの登録のフォームが表示されるので入力を行います。Application nameには任意の名前をつけてください。ユーザがアカウント情報をLaravelに渡していいかどうか確認する際のAuthorize画面に設定した名前が表示されます。Homepage URLはローカル環境なので開発サーバのURLを指定しています。Authorization callback URLはhttp://127.0.0.1:8000/auth/callbackを設定しています。このルーティングは後ほどLaravel側で追加します。入力が完了したら”Register application”ボタンをクリックしてください。ここで入力した値は後から変更も可能です。

OAuth Applicationの登録
OAuth Applicationの登録

Client IDとClient Secretsが表示される画面が表示されます。Client Secretsについては”Generate new client secret”ボタンをクリックしてください。

Client IDとSecret
Client IDとSecret

Client IDとClient SecretsについてはLaravelの.envファイルに設定を行います。


GITHUB_CLIENT_ID="613b61cbfe574b0a96ee"
GITHUB_CLIENT_SECRET="XXXXXXXXXXXXXXXXXXXXXX4b3599927"

Laravel Socialiteの設定

services.phpファイルの更新

config/services.phpファイルを開いてgithubの情報を追加します。client_idとclient_secretについては先ほどGitHubから取得した値を設定した環境変数を指定しています。redirectの値についても環境変数を設定しているので値は.envファイルに追加します。


<?php

return [

//略
    'github' => [
        'client_id' => env('GITHUB_CLIENT_ID'),
        'client_secret' => env('GITHUB_CLIENT_SECRET'),
        'redirect' => env('GITHUB_CALLBACK'),
    ],
];

GITHUB_CALLBACKに設定する値はGitHubでのOAuth Application登録画面のAuthorization Callback URLに設定した値と同じ値を設定します。異なる場合はエラーになります。


GITHUB_CLIENT_ID="613b61cbfe574b0a96ee"
GITHUB_CLIENT_SECRET="XXXXXXXXXXXXXXXXXXXXXX4b3599927"
GITHUB_CALLBACK="http://127.0.0.1:8000/auth/callback"

ルーティングの追加

/auth/callbackをルーティングファイルであるweb.phpファイルに追加します。


use Laravel\Socialite\Facades\Socialite;
//略
Route::get('/auth/redirect', function () {
    return Socialite::driver('github')->redirect();
});

Route::get('/auth/callback', function () {

    $socialiteUser = Socialite::driver('github')->user();
    dd($socialiteUser);

});

/auth/callbakの他に/auth/redirectのルーティングを追加しています。このルーティングにアクセスするとLaravelアプリケーションからGitHubへのアクセスが行われます。ユーザがログイン画面でクリックするボタンにはこのURLを指定します。

ログインボタンの設定

ログインボタンをログインページに表示させるためresouces/views/auth/login.blade.phpファイルを開きます。Breezeのインストール時に作成されるファイルです。

ログインボタンの下にGitHubへのログインボタンを追加します。svgのタグは少し長いですがGitHubのロゴなのでここではあまり重要ではありません。aタグのhrefに/auth/redirectが指定されていることを確認してください。


    </form>
    <div class="text-center my-2">
        or
    </div>
    <div class="w-full">
        <a href="/auth/redirect" class="w-full space-x-2 flex justify-center items-center px-4 py-2 border hover:bg-gray-100">
            <svg aria-hidden="true" focusable="false" role="img" viewBox="0 0 16 16" width="24" height="24" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"></path></svg>
            <span>Sign up with GitHub</span>
        </a>
    </div>
</x-guest-layout>

Tailwind CSSを利用しているため利用したclassを適用するためにnpm run buildコマンドを実行してCSSのビルドを行います。ビルド後ブラウザからログイン画面に移動するとEmail/Passwordのログインフォームと”Sign up with GitHub”のボタンが表示されます。

"Sign up with GitHub"
“Sign up with GitHub”

ボタンをクリックするとAuthorize画面が表示されます。Client IDやcallbackのURLがLaravel側とGitHub側の設定値が異なる場合などにはAuthorize画面は表示されないので正しい値が設定されているか確認してください。

GitHubのOAuthのアプリケーション登録画面で設定したアプリケーション名(Socialite Test)もここで利用されていることがわかります。GitHubアカウントへのアクセスを許可するかどうかのAuthorize画面です。AuthrorizeボタンをクリックするとGitHubアカウントの情報をLaravel側から取得するために必要なCodeが渡されます。渡されたCodeを利用してアカウント情報を取得するのがLaravel Socialiteの役割の一つです。

Authorize画面
Authorize画面

現在開いているブラウザ上でGithHubのサイトへのログインが完了していない場合にはGitHubへのログイン画面が表示されるのでGitHubへのログインを行なってください。

GitHubへのログイン画面
GitHubへのログイン画面

Authorizeボタンをクリックするとブラウザには/auth/callbakで設定した$socialiteUserの情報が表示されます。これはGitHubに設定しているアカウント情報です。ここまでの設定でGitHubからアカウント情報を取得することができるようになりました。

GitHubのアカウント情報
GitHubのアカウント情報

この情報を利用してLaravel上のユーザの作成を行います。GitHubから取得したデータの中からidとnameとemailを利用しています。その他にもさまざまな情報が取得できているので必要なものを選択してください。他のProviderを利用した場合にどのProviderから取得した情報か識別できるようにproviderの情報も保存をしておきます。


Route::get('/auth/callback', function () {

    $socialiteUser = Socialite::driver('github')->user();

    $user = User::updateOrCreate([
        'provider_id' => $socialiteUser->id,
        'provider' => 'github',
    ], [
        'name' => $socialiteUser->name,
        'email' => $socialiteUser->email,
    ]);
 
    Auth::login($user);

    return redirect('/dashboard');
 
});

providerとprovider_idはUserテーブルに存在していないので追加を行います。デフォルトで存在するUserテーブルのmigrationファイルに追加します。


public function up(): void
{
    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('email')->unique();
        $table->timestamp('email_verified_at')->nullable();
        $table->string('password');
        $table->string('provider');
        $table->string('provider_id');
        $table->rememberToken();
        $table->timestamps();
    });
}

providerとprovider_idの情報をuserテーブルに登録できるようにするためUser.phpファイルの$fillableの配列に追加します。


protected $fillable = [
    'name',
    'email',
    'password',
    'provider',
    'provider_id'
];

追加後テーブルを再作成するためphp artisan migrateコマンドを実行します。


 % php artisan migrate:refresh

   WARN  Migration table not found.  

   INFO  Preparing database.  

  Creating migration table ............................................. 5ms DONE

   INFO  Running migrations.  

  2014_10_12_000000_create_users_table ................................. 3ms DONE
  2014_10_12_100000_create_password_reset_tokens_table ................. 2ms DONE
  2019_08_19_000000_create_failed_jobs_table ........................... 2ms DONE
  2019_12_14_000001_create_personal_access_tokens_table ................ 3ms DONE

テーブルを作成後、ログイン画面の”Sign up with GitHub”をクリックします。Authorize画面でアクセスを許可したので二度目のアクセスからはAuthroize画面が表示されることはありません。

もしアクセスを許可したアプリケーションの情報を削除したい場合にはGitHubのメニューのIntegrationsからApplicationsを選択して、Authorized OAuth Appsから削除することができます。削除した後に再度”Sign up with GitHub”をクリックすると再度Authorize画面が表示されます。

“Sign up with GitHub”ボタンクリックすると”SQLSTATE[23000]:Integrity constraint violation not null constraint failed”のエラーが発生します。今回利用したGitHubアカウントのnameが設定されていないためユーザ情報を追加することができません。password列についてもOAuthでは必要でないため同様の理由でエラーが発生します。そのため値がnullになる可能性がある列にはnullableを設定してnullの値でも許可するようにマイグレーションフファイルの更新を行います。


public function up(): void
{
    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->string('name')->nullable();
        $table->string('email')->unique();
        $table->timestamp('email_verified_at')->nullable();
        $table->string('password')->nullable();
        $table->string('provider');
        $table->string('provider_id');
        $table->rememberToken();
        $table->timestamps();
    });
}

マイグレレーションファイルを更新後はphp artisan migrate:refreshコマンドでテーブルの再作成を行います。

再度ログイン画面の”Sign up with GitHub”をクリックするとダッシュボード画面にリダイレクトされます。

ダッシュボード画面
ダッシュボード画面

ログインした後はLaravelのEmail/Passwodでログインした時と同じ方法で管理されるので/loginにアクセスすると/dashboardにリダイレクトされます。ログアウトしたい場合は右上にあるボタン(ユーザ名がないため上の画像ではブランク)をクリックするとドロップダウンメニューでログアウトが表示されるのでログアウトを行うことができます。再度ログインしたい場合にはログイン画面の”Sign up with GitHub”ボタンからログインすることができます。一度Sign UpをしているのでSign In等に分ける必要がありますが本書は動作確認を目的としているのでSign Upのままにしています。

ここまでの説明でLaravel Socialiteの設定は完了しました。OAuthはLaravel限定の機能ではないのでLaravel Socialiteでどのような処理が行われているか理解できればLaravel以外でも役に立つ知識になります。

次は実際にコードを見ながらどのような処理が行われているのか確認していきます。

ルーティング/auth/redirectの処理

ログインページに設定した”Sign up with GitHub”ボタンは/auth/redirectへのリンクが設定されているのでクリックすると/auth/redirectに移動します。

web.phpファイルの/auth/redirectルーティングの処理を見るとSocialite::driver(‘github’)が実行されています。Socialite::driver(‘github’)を実行することで作成されるインスタンスが何かを確認します。


Route::get('/auth/redirect', function () {
    return Socialite::driver('github')->redirect();
});

Laravel SocialiteのService Provider(SocialiteServiceProvider.php)からSocialiteファサードの実体はSocialiteManagerということがわかるのでsocialite/src/SocialiteManager.phpファイルの中身を確認します。SocialiteManagerにはdriverメソッドがありませんが継承しているManagerクラスにdriverメソッドがあるのでIlluminate\Support\Managerを確認すると引数にgithubを指定しているためcreateGithubDriverが実行されます。createGithubDriverメソッドはSocialiteManager.phpに記述されています。引数によって実行されるメソッドが変わります。googleであればcreateGoogleDriverメソッドとなります。


protected function createGithubDriver()
{
    $config = $this->config->get('services.github');

    return $this->buildProvider(
        GithubProvider::class, $config
    );
}

createGithubDriverメソッドの$configに保存されるのはSocialiteを設定する時に追加したservices.phpファイルのgithubの値です。


'github' => [
    'client_id' => env('GITHUB_CLIENT_ID'),
    'client_secret' => env('GITHUB_CLIENT_SECRET'),
    'redirect' => 'http://localhost:3000/auth/callback',
],

buildProviderメソッドの引数にはGithubProviderクラスと$configが指定されています。buildProviderメソッドを確認するとGithubProviderインスタンスが戻されていることがわかります。


public function buildProvider($provider, $config)
{
    return new $provider(
        $this->container->make('request'), $config['client_id'],
        $config['client_secret'], $this->formatRedirectUrl($config),
        Arr::get($config, 'guzzle', [])
    );
}

ここまでの確認でSocialite::driver(‘github’)は最終的にはGithubProviderインスタンスを作成していることがわかります。Socialite::driverメソッドの引数がgoogleの場合はGoogleProviderインスタンスが作成されることになります。Socialite::driverメソッドは引数に設定したProviderの名前に対応するインスタンスを作成する処理だということが理解できました。

GithubProviderクラスはAbstratcProviderクラスを継承しているのでGithubProviderのインスタンスを作成する際に設定した引数は__constructメソッドで以下のように設定されます。


public function __construct(Request $request, $clientId, $clientSecret, $redirectUrl, $guzzle = [])
{
    $this->guzzle = $guzzle;
    $this->request = $request;
    $this->clientId = $clientId;
    $this->redirectUrl = $redirectUrl;
    $this->clientSecret = $clientSecret;
}

Socialite::driver(‘github’)が理解できたので次はredirectメソッドの中身を確認します。AbstractProviderクラスがredirectメソッドを持ちAbstractProvider.phpファイルのredirectメソッドの説明には”Redirect the user of the application to the provider’s authentication screen.”と記述されているのでGitHubの認証画面にリダイレクトさせる処理だということがわかります。

実際にコードを見ていきます。$stateはランダム40桁の文字数で作成を行いSessionに保存しています。$stateの値はGitHubに送信し、GitHubでの認証後にGitHubから戻され、同じ値かチェックをするために利用します。PKCEはデフォルトでは利用していません。


public function redirect()
{
    $state = null;

    if ($this->usesState()) {
        $this->request->session()->put('state', $state = $this->getState());
    }

    if ($this->usesPKCE()) {
        $this->request->session()->put('code_verifier', $this->getCodeVerifier());
    }

    return new RedirectResponse($this->getAuthUrl($state));
}

getAuthUrlメソッドを確認するとここでようやくGitHubのURL(https://github.com/login/oauth/authorize)を確認することができます。


protected function getAuthUrl($state)
{
    return $this->buildAuthUrlFromBase('https://github.com/login/oauth/authorize', $state);
}

buildAuthUrlFromBaseメソッドでリクエストと一緒に送信するパラメータの設定を行っています。


protected function buildAuthUrlFromBase($url, $state)
{
    return $url.'?'.http_build_query($this->getCodeFields($state), '', '&', $this->encodingType);
}

protected function getCodeFields($state = null)
{
    $fields = [
        'client_id' => $this->clientId,
        'redirect_uri' => $this->redirectUrl,
        'scope' => $this->formatScopes($this->getScopes(), $this->scopeSeparator),
        'response_type' => 'code',
    ];

    if ($this->usesState()) {
        $fields['state'] = $state;
    }

    if ($this->usesPKCE()) {
        $fields['code_challenge'] = $this->getCodeChallenge();
        $fields['code_challenge_method'] = $this->getCodeChallengeMethod();
    }

    return array_merge($fields, $this->parameters);
}

実際に”Sign Up with GitHub”のボタンをクリックすると以下のパラメータをつけてGitHubのURLにリクエストが送信されます。


https://github.com/login/oauth/authorize?client_id=613b61cbfe574b0a96ee&redirect_uri=http://127.0.0.1:8000/auth/callback&scope=user:email&response_type=code&state=uUuqSX4ikStz0eXLyNJ4Vwx1fJljJP0SOHB6rIlz

ブラウザのネットワークタブを見ると送信しているパラメータの内容をすっきりとした形で確認することができます。


client_id: 613b61cbfe57b0a96aee
redirect_uri: http://127.0.0.1:8000/auth/callback
scope: user:email
response_type: code
state: uUuqSX4ikStz0eXLyNJ4Vwx1fJljJP0SOHB6rIlz

ここまでの説明で/auth/redirectで行われている処理はGitHub(Provider)の認証画面に必要となる内容を送信するリクエストを作成しているだけということがわかりました。

ルーティング/auth/callbackの処理

ルーティング/auth/callbackの設定はGitHubのOAuth Applicationの作成時とservices.phpファイルのredirect_urlで設定を行っているURLです。

このURLへのリクエストはGitHubから実行されます。”Sign Up with GitHub”ボタンをクリック後のネットワークタブを見ると確認することができます。3つ目のcallbackへのInitiatorがgithub.comになっておりcallbackの後にはcodeとstateのパラメータがついていることも確認できます。codeとstateがGitHubから戻されていることになります。

ネットワークタブの確認
ネットワークタブの確認

GitHubから実行される/auth/callbackの処理を確認していきます。Socialite::driver(‘github’)のuserメソッドが実行されています。Socialite::driver(‘github’)はGitHubProviderのインスタンスであることは/auth/redirectで確認しているのでGitHubProviderのuserメソッドを確認します。


$socialiteUser = Socialite::driver('github')->user();

userメソッドはAbstractProvider.phpファイルの中に記述されています。


public function user()
{
    if ($this->user) {
        return $this->user;
    }

    if ($this->hasInvalidState()) {
        throw new InvalidStateException;
    }

    $response = $this->getAccessTokenResponse($this->getCode());

    $this->user = $this->mapUserToObject($this->getUserByToken(
        $token = Arr::get($response, 'access_token')
    ));

    return $this->user->setToken($token)
                ->setRefreshToken(Arr::get($response, 'refresh_token'))
                ->setExpiresIn(Arr::get($response, 'expires_in'))
                ->setApprovedScopes(explode($this->scopeSeparator, Arr::get($response, 'scope', '')));
}

hasInvalidStateはsessionに保存されているstateの値とURLのパラメータに含まれているstateの値が同じかチェックを行っています。異なる場合にはInvalidStateExceptionがthrowされます。


protected function hasInvalidState()
{
    if ($this->isStateless()) {
        return false;
    }

    $state = $this->request->session()->pull('state');

    return empty($state) || $this->request->input('state') !== $state;
}

stateの値が一致した場合には次のgetAccessTokenResponseメソッドが実行されます。引数のgetCodeではURLのパラメータのcodeの値を取得しています。


protected function getCode()
{
    return $this->request->input('code');
}

getAccessTokenResponseメソッドではcodeの値だけではなくclient_id、client_secretを利用してTokenを取得するためにGitHubにPOSTリクエストを送信しています。


public function getAccessTokenResponse($code)
{
    $response = $this->getHttpClient()->post($this->getTokenUrl(), [
        RequestOptions::HEADERS => $this->getTokenHeaders($code),
        RequestOptions::FORM_PARAMS => $this->getTokenFields($code),
    ]);

    return json_decode($response->getBody(), true);
}

protected function getTokenHeaders($code)
{
    return ['Accept' => 'application/json'];
}

protected function getTokenFields($code)
{
    $fields = [
        'grant_type' => 'authorization_code',
        'client_id' => $this->clientId,
        'client_secret' => $this->clientSecret,
        'code' => $code,
        'redirect_uri' => $this->redirectUrl,
    ];

    return $fields;
}

getTokenUrlではGitHubの下記のURLを指定しています。


protected function getTokenUrl()
{
    return 'https://github.com/login/oauth/access_token';
}

getAccessTokenResponseメソッドでPOSTリクエストを送信後、GitHubから戻される値にはアクセストークンが含まれています。


array (
  'access_token' => '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',
  'token_type' => 'bearer',
  'scope' => 'user:email',
)  

アクセストークンを取得後はアクセストークンを引数にgetUserByTokenメソッドを実行しています。


$this->user = $this->mapUserToObject($this->getUserByToken(
    $token = Arr::get($response, 'access_token')
));

getUserByTokenメソッドではGitHubのhttps://api.github.com/userに対してアクセストークンをつけたGETリクエストを送信してユーザ情報を取得していることがわかります。emailについてはさらにgetEmailByTokenメソッドの中でアクセストークンをつけたGETリクエストを送信してGitHubからEmailを取得しています。


protected function getUserByToken($token)
{
    $userUrl = 'https://api.github.com/user';

    $response = $this->getHttpClient()->get(
        $userUrl, $this->getRequestOptions($token)
    );

    $user = json_decode($response->getBody(), true);

    if (in_array('user:email', $this->scopes, true)) {
        $user['email'] = $this->getEmailByToken($token);
    }

    return $user;
}

codeとClient IDとClient Secretを利用してアクセストークンを取得してアクセストークンを利用してユーザ情報とメールアドレスを取得することがわかりました。つまりOAuthではアカウント情報を取得するためにはアクセストークンが必要であることがわかります。

GitHubから取得した情報は最終的には以下の情報になります。

GitHubから取得したユーザ情報
GitHubから取得したユーザ情報

ユーザ情報の中にアクセストークンの値以外にrefresh_tokenやexpires.inを設定していますがGitHubからはそれらの値は戻されないのでnullが設定されます。


return $this->user->setToken($token)
            ->setRefreshToken(Arr::get($response, 'refresh_token'))
            ->setExpiresIn(Arr::get($response, 'expires_in'))
            ->setApprovedScopes(explode($this->scopeSeparator, Arr::get($response, 'scope', '')));

/auth/callbackではGitHubから取得した情報を利用してユーザの作成を行っています。provider_idとproviderが同じ値を持つユーザが存在すれば更新を行い、存在しない場合には作成することになります。


$user = User::updateOrCreate([
    'provider_id' => $socialiteUser->id,
    'provider' => 'github',
], [
    'name' => $socialiteUser->name,
    'email' => $socialiteUser->email,
]);

TablePlusというデータベース管理ソフトを利用してSQLiteのデータベースを見るとユーザ情報が登録されていることがわかります。

Userテーブルの確認
Userテーブルの確認

作成したユーザはAuth::loginでログイン処理が行われ、ダッシュボードにリダイレクトされます。


Auth::login($user);

return redirect('/dashboard');

Auth::login($user)でログイン後は通常の認証機能を利用するためOAuthのProviderであるGitHubを意識する必要はありません。

Laravel Socialiteではどのような処理が行われているか理解することができました。