Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

JimNayzium's avatar

SPA authentication to Laravel 11 (different domain) backend API with Sanctum

domain-one.com = SvelteKit SPA

domain-two.com = hidden, backend only, Laravel 11 API delivery

I want my users to be able to login using email+password registration, which I got working using only sanctum (and not even fortify.)

BUT, I also want my users to be able to login using Google gmail/authentication methods.

I got Socialite working on the redirect methods explained in Jeffery Way's awesome tutorials, but am nervous that the way I am doing it will be sunsetted right as I go live.

Can anyone confirm the socialite login method using the google cloud service methods that involves the /auth/google/callback redirect method will continue working without needing a full revamp soon?

When I login to my google cloud console it keeps showing me this nasty message and makes me believe I will need a pretty healthy change to what I have working.

0 likes
1 reply
LaryAI's avatar
Level 58

To address your question about SPA authentication with Laravel 11 using Sanctum and Socialite for Google authentication, let's break down the solution into manageable steps. We'll cover both email/password authentication and Google OAuth authentication.

1. Setting Up Sanctum for SPA Authentication

First, ensure that Sanctum is properly set up in your Laravel backend. Sanctum provides a simple way to authenticate single-page applications (SPAs) using cookies.

Install Sanctum

composer require laravel/sanctum

Publish Sanctum Configuration

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate

Configure Sanctum

In your config/sanctum.php, ensure the stateful configuration includes your frontend domain:

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'domain-one.com')),

In your config/cors.php, configure CORS to allow your frontend domain:

'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_origins' => ['https://domain-one.com'],
'allowed_methods' => ['*'],
'allowed_headers' => ['*'],
'max_age' => 0,
'supports_credentials' => true,

Middleware

Ensure api middleware group in app/Http/Kernel.php includes EnsureFrontendRequestsAreStateful:

'api' => [
    \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

2. Email/Password Authentication

Create routes and controllers for login and registration.

Routes

In routes/api.php:

use App\Http\Controllers\AuthController;

Route::post('/login', [AuthController::class, 'login']);
Route::post('/register', [AuthController::class, 'register']);
Route::post('/logout', [AuthController::class, 'logout'])->middleware('auth:sanctum');

AuthController

Create AuthController to handle authentication:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
use Illuminate\Support\Facades\Hash;

class AuthController extends Controller
{
    public function register(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:8|confirmed',
        ]);

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);

        return response()->json(['message' => 'User registered successfully']);
    }

    public function login(Request $request)
    {
        $request->validate([
            'email' => 'required|string|email',
            'password' => 'required|string',
        ]);

        if (!Auth::attempt($request->only('email', 'password'))) {
            return response()->json(['message' => 'Invalid credentials'], 401);
        }

        return response()->json(['message' => 'Login successful']);
    }

    public function logout(Request $request)
    {
        $request->user()->currentAccessToken()->delete();
        return response()->json(['message' => 'Logged out successfully']);
    }
}

3. Google OAuth Authentication with Socialite

Install Socialite

composer require laravel/socialite

Configure Socialite

Add your Google credentials to .env:

GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GOOGLE_REDIRECT_URI=https://domain-two.com/auth/google/callback

Socialite Routes

In routes/web.php:

use App\Http\Controllers\SocialiteController;

Route::get('/auth/google/redirect', [SocialiteController::class, 'redirectToGoogle']);
Route::get('/auth/google/callback', [SocialiteController::class, 'handleGoogleCallback']);

SocialiteController

Create SocialiteController to handle Google OAuth:

namespace App\Http\Controllers;

use Laravel\Socialite\Facades\Socialite;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;

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

    public function handleGoogleCallback()
    {
        $googleUser = Socialite::driver('google')->stateless()->user();

        $user = User::firstOrCreate(
            ['email' => $googleUser->getEmail()],
            [
                'name' => $googleUser->getName(),
                'password' => Hash::make(uniqid()), // Generate a random password
            ]
        );

        Auth::login($user);

        return redirect('https://domain-one.com'); // Redirect to your SPA
    }
}

4. Frontend Integration

In your SvelteKit SPA, you can use the fetch API to interact with your Laravel backend for login, registration, and Google OAuth.

Example Login Request

async function login(email, password) {
    const response = await fetch('https://domain-two.com/api/login', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        credentials: 'include',
        body: JSON.stringify({ email, password }),
    });

    const data = await response.json();
    if (response.ok) {
        console.log('Login successful:', data);
    } else {
        console.error('Login failed:', data);
    }
}

Example Google OAuth Redirect

function redirectToGoogle() {
    window.location.href = 'https://domain-two.com/auth/google/redirect';
}

Conclusion

This setup should allow you to authenticate users using both email/password and Google OAuth in your SvelteKit SPA with a Laravel 11 backend. Ensure you keep an eye on any updates from Google regarding OAuth to make necessary adjustments in the future.

Please or to participate in this conversation.