Search code examples
laravelsingle-sign-onlaravel-passportlaravel-socialite

Laravel Passport & Laravel Socialite for SSO


I am trying to create a Laravel application which will handle authorization for other first-party Laravel applications. My current flow is:

  1. User from application A presses the login button
  2. They get redirected to application B (Laravel Passport application)
  3. If they are logged in, they get redirected to the callback
  4. If they are not logged in, they are prompted to login with their google account and then they get redirected back to the callback. My current problem is that after the user logins, they won't get redirected to the callback (so to application A) and instead the process stops at the callback.

My SocialiteController.php

class SocialiteController extends Controller
{
    public function redirectProvider()
    {
        return Socialite::driver('github')->stateless()->redirect();
    }

    public function callbackProvider()
    {
        // We get the user who is trying to login.
        $githubUser = Socialite::driver('github')->stateless()->user();

        // Check if the user exists, otherwise just create it.
        $user = User::updateOrCreate([
            'email' => $githubUser->email
        ], [
            'name' => $githubUser->name,
            'email' => $githubUser->email,
            'github_token' => $githubUser->token,
            'github_refresh_token' => $githubUser->refresh_token,
            'last_login' => now()
        ]);

        // Create a token for authenticating the user

        Auth::guard('api')->setUser($user);

        // They should get redirected to the application A with the code query param required for getting the bearer token.

    }
}

My config/auth.php:

'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],

'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'api' => [
            'driver' => 'passport',
            'provider' => 'users',
        ]
    ],

My config/passport.php guard

'guard' => 'web',

My routes:

Route::controller(SocialiteController::class)->group(function () {
    Route::get('redirect', 'redirectProvider')->name('socialite.redirect');
    Route::get('callback', 'callbackProvider')->name('socialite.callback');
});

Example of url for authorization: http://localhost:7003/oauth/authorize?client_id=9a622876-4a3a-4046-a41d-76b303fa0f4e&redirect_uri=http://localhost:7005&response_type=code&scope=*


Solution

  • After a few hours of trying things out, I have remembered about: redirect()->intended(); so I was able to pull the authorize url from the session and redirect the user back. The new callback method:

    public function callbackProvider()
        {
            // We get the user who is trying to login.
            $githubUser = Socialite::driver('github')->stateless()->user();
    
            // Check if the user exists, otherwise just create it.
            $user = User::updateOrCreate([
                'email' => $githubUser->email
            ], [
                'name' => $githubUser->name,
                'email' => $githubUser->email,
                'github_token' => $githubUser->token,
                'github_refresh_token' => $githubUser->refresh_token,
                'last_login' => now()
            ]);
    
            // Create a token for authenticating the user
    
            Auth::guard('api')->setUser($user);
    
            return redirect()->intended();
        }