is nobody using Sanctum for SPA and social network login? or should the approach be somehow different?
Sanctum with Socialite and SPA
Sanctum with Socialite and SPA
I'm having hard times trying to get Socialite and Sanctum running on SPA webiste... i would like to use SPA authentication as recommended in laravel documantation sanctum#spa-authentication (not allowed to post links 😅). I would also like to login user right away.
the flow i am trying to use is clicking link on SPA -> API server redirects to social network -> (social network login) -> callback to API server where i create and log in user -> redirect back to SPA. both SPA and API are on the same domain.
is it even possible? event after few hours i am not able set it right... i suppose i cannot use Socialite Stateless Authentication socialite#stateless-authentication because it wont't work with the sanctum session authentication ... so i end up with
api routes:
Route::group([
'middleware' => 'web',
'excluded_middleware' => EnsureFrontendRequestsAreStateful::class,
], function () {
Route::get('auth/{provider}', [LoginController::class, 'redirectToProvider']);
Route::get('auth/{provider}/callback', [LoginController::class, 'handleProviderCallback']);
});
and LoginController:
public function redirectToProvider($provider): RedirectResponse
{
return Socialite::driver($provider)->redirect();
}
public function handleProviderCallback($provider): RedirectResponse
{
$user = Socialite::driver($provider)->user();
$newUser = User::firstOrCreate([
'email' => $user->getEmail()
], [
'email_verified_at' => now(),
'name' => $user->getName(),
'status' => true,
'provider' => $provider,
'provider_id' => $user->getId(),
]);
Auth::login($newUser);
return redirect(env('SPA_URL') . '/registration-followup');
}
but when i send axios request from registration-followup page to API server, user is not logged in.
This is not the proper way to login in with a SPA.
You need to send a POST request instead of a get request when you are login in with a separated SPA.
Route::post('auth/{provider}/callback', [LoginController::class, 'handleProviderCallback']);
- SPA site.com/login click google login button
- button take you to google sign in and you sign in there
- google redirect you back to SPA site.com/login with a code
- You send that code to the AP site.com/api/login/google/callback using a post request
- SPA site.com sign in
The documentation does not explain this and had to figure it out.
For a SPA you don't need to use route Route::get('auth/{provider}', [LoginController::class, 'redirectToProvider']);
This is how I did it using Nuxt.js using nuxt auth
google: {
clientId: process.env.GOOGLE_CLIENT_ID,
codeChallengeMethod: "",
responseType: "code",
endpoints: {
token: "/api/login/google/callback",
userInfo: "/user",
},
grantType: "authorization_code",
},
Route::post('/login/{provider}/callback', [SocialAuthController::class,'handleProviderCallback']);
*/
public function handleProviderCallback($provider)
{
$validated = $this->validateProvider($provider);
if (!is_null($validated)) {
return $validated;
}
$providerUser = Socialite::driver($provider)->stateless()->user();
$providerId = Provider::where('provider_id', $providerUser->getId())->first();
if ($providerId) {
$updateUser = User::where('email', $providerUser->getEmail())->first();
$token = $updateUser->createToken('token-name')->plainTextToken;
} else {
$createUser = User::firstOrCreate([
'email' => $providerUser->getEmail(),
'email_verified_at' => now(),
'name' => $providerUser->getName(),
'avatar_path' => $providerUser->getAvatar()
]);
$createUser->providers()->updateOrCreate([
'provider' => $provider,
'provider_id' => $providerUser->getId(),
]);
$token = $createUser->createToken('token-name')->plainTextToken;
}
return response()->json([
'token_type' => 'bearer',
'access_token' => $token,
], 200);
}
protected function validateProvider($provider)
{
if (!in_array($provider, ['facebook', 'google'])) {
return response()->json(['error' => 'Please login using facebook or google'], 422);
}
}
Please or to participate in this conversation.