laravel ✕ OAuth2.0を試すためにリダイレクトURLをlaravel側で実装してGoogle側に設定する

## 概要

laravelを用いてOAuth系の実装をしてみたい。
Socialiteというlaravelのライブラリを使うことで楽に実装できるらしいので入れてみた。
どうやら.envに

- GOOGLE_CLIENT_ID
- GOOGLE_CLIENT_SECRET
- GOOGLE_REDIRECT_URI

などのキーバリューを設定する必要があるらしく、 GOOGLE_REDIRECT_URIはlaravel側でルーティングを実装し、Google側に設定する必要があるらしい。

リダイレクトURIを実装してGoogle側に設定する方法を簡単にまとめる。

## 実装内容

- 俗に言う「※1AOuth認証」を試す
- laravelでGoogle認証ページへのリダイレクトルートを作成
- コールバックをうけとり、Google側の情報（メアド、名前）を用いてlaravel側アプリにログイン、laravel側にメアドで検索してユーザー情報がなければ作成してログイン

## 前提

- laravelにライブラリの[Socialite](https://readouble.com/laravel/12.x/ja/socialite.html)が導入済みであること
- usersテーブルが存在すること
- 下記の内容が実施済みであり.envに下記のキーが定義され、値が設定されていること
    - `GOOGLE_CLIENT_ID`
    - `GOOGLE_CLIENT_SECRET`

https://qiita.com/miriwo/items/9485f897045681f820bc

- テストに使用するGoogleアカウントがGoogle CloudのOAuthのクライアント設定でテストユーザーとして許可されていること　参考→ [Google Auth Platform クライアントの設定を検証するためのテストユーザーを追加する](https://qiita.com/miriwo/items/289829779b3ceef9d3b4)
- ローカル環境は80ポートで提供されているものとすること
- 認証ライブラリのJetstreamが導入されていること

## 方法

1. laravelのweb.phpに下記のようなコードを記載

    ```routes/web.php
    // Googleの認証ページへのリダイレクト
    Route::get('/auth/redirect', function () {
        return Socialite::driver('google')
            ->scopes(['email', 'profile'])
            ->redirect();
    })->name('google.redirect');
    
    // Googleからのコールバックを受け取る
    Route::get('/auth/callback', function () {
        try {
            $googleUser = Socialite::driver('google')->user();
        } catch (Exception $e) {
            Log::error($e);
            return redirect(route('home'));
        }
    
        // ユーザーが既に存在するか確認
        $user = User::where('email', $googleUser->getEmail())->first();
    
        if (!$user) {
            // ユーザーが存在しない場合、新規作成
            $user = User::create([
                'name' => $googleUser->getName(),
                'email' => $googleUser->getEmail(),
                'google_id' => $googleUser->getId(),
                'password' => Hash::make(Str::random(16)),
            ]);
        }
    
        // ユーザーをログインさせる
        Auth::login($user);
    
        // リダイレクト先を指定
        return redirect(route('dashboard'));
    })->name('google.callback');
    ```

1. 追記後のweb.phpのすべての内容は下記

    ```web.php
    <?php
    
    use App\Models\User;
    use Illuminate\Support\Facades\Auth;
    use Illuminate\Support\Facades\Hash;
    use Illuminate\Support\Facades\Log;
    use Illuminate\Support\Facades\Route;
    use Illuminate\Support\Str;
    use Laravel\Socialite\Facades\Socialite;
    
    Route::get('/', function () {
        return view('welcome');
    })->name('home');
    
    Route::middleware([
        'auth:sanctum',
        config('jetstream.auth_session'),
        'verified',
    ])->group(function () {
        Route::get('/dashboard', function () {
            return view('dashboard');
        })->name('dashboard');
    });
    
    // Googleの認証ページへのリダイレクト
    Route::get('/auth/redirect', function () {
        return Socialite::driver('google')
            ->scopes(['email', 'profile'])
            ->redirect();
    })->name('google.redirect');
    
    // Googleからのコールバックを受け取る
    Route::get('/auth/callback', function () {
        try {
            $googleUser = Socialite::driver('google')->user();
        } catch (Exception $e) {
            Log::error($e);
            return redirect(route('home'));
        }
    
        // ユーザーが既に存在するか確認
        $user = User::where('email', $googleUser->getEmail())->first();
    
        if (!$user) {
            // ユーザーが存在しない場合、新規作成
            $user = User::create([
                'name' => $googleUser->getName(),
                'email' => $googleUser->getEmail(),
                'google_id' => $googleUser->getId(),
                'password' => Hash::make(Str::random(16)),
            ]);
        }
    
        // ユーザーをログインさせる
        Auth::login($user);
    
        // リダイレクト先を指定
        return redirect(route('dashboard'));
    })->name('google.callback');    
    ```

1. .envに下記の内容を記載

    ```.env
    GOOGLE_REDIRECT_URI=http://localhost:80/auth/redirect
    ```

1. `config/services.php`に下記の内容を記載

    ```config/services.php
    'google' => [
        'client_id' => env('GOOGLE_CLIENT_ID'),
        'client_secret' => env('GOOGLE_CLIENT_SECRET'),
        'redirect' => env('GOOGLE_REDIRECT_URI'),
    ],
    ```

1. .envの設定を反映させる作業を実施（sailを使っているなら`$ ./vendor/bin/sail down`を実行して`$    ./vendor/bin/sail up -d`を実行）
1. 下記の手順でGoogle CloudにOAuthの認証トークンを返すURIを設定
    1. Google Cloud → APIとサービス → サイドバーの「OAuth同意画面」 → サイドバーの「クライアント」をクリック
    1. 「承認済みのリダイレクト URI」に`http://localhost:80/auth/callback`と記載

        ![CleanShot 2025-05-29 at 15.53.41@2x.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/926b3429-e334-47b4-ba44-6c8cfd23f0b4.jpeg)

1. `$ npm run dev`を実行（筆者はsailを使っているので`$ sail npm run dev`を実行）
1. (http://localhost:80/auth/callback)[http://localhost:80/auth/callback]にアクセスし下記のような画面が出ることを確認

    ![CleanShot 2025-05-30 at 11.23.11@2x.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/c3f8ae10-4525-4f3e-b35c-0a48c11f1417.jpeg)

1. ログイン済みアカウントか新たに「別のアカウントを使用」からログインを実施（このアカウントはGoogle CloudのOAuthのクライアント設定でテストユーザーとして許可されているものを使用）
1. Googleのアカウント選択して下記の画面に遷移したら「次へ」をクリック

    ![CleanShot 2025-05-30 at 11.26.39@2x.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/272388fa-339f-476b-af2a-caceaddaa70d.jpeg)

1. ログインした状態で/dashboardの画面が表示されること

    ![CleanShot 2025-05-30 at 12.16.37@2x.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/738dc223-618a-4391-98d7-d97c94898824.jpeg)

1. DBのusersテーブルにログイン中ユーザーのレコードが作成されている

※1：認可プロトコルであるOAuthによって指定された取得可能な情報を用いて認証を行うこと

## 参考物件

https://readouble.com/laravel/12.x/ja/socialite.html

https://laravel.com/docs/12.x/socialite

https://github.com/laravel/socialite?tab=readme-ov-file

https://socialiteproviders.com/

https://socialiteproviders.com/Google-Plus/