ix
ix

informatix

PL version Book a discovery call
Home / Blog / Inertia.js Authentication with Laravel and React [2026]
• 8 min read •

Inertia.js Authentication with Laravel and React [2026]

Authentication in Inertia.js is ordinary Laravel session auth — no tokens, no OAuth handshake. Breeze or manual setup, login and registration forms, password reset, policies and shared auth props.

Inertia.js Authentication with Laravel and React [2026]
Web development

Authentication in an Inertia.js application is ordinary Laravel session authentication. There are no tokens, no OAuth handshake and no API guard for the web client. The React login form posts to a Laravel route, Laravel validates the credentials, regenerates the session and redirects to the dashboard. This guide shows both paths: the fast one with the Laravel React starter kit, and the manual one for existing applications.

Key takeaway: The short version — use Laravel's session guard, protect routes with the auth middleware, share the authenticated user through HandleInertiaRequests, and authorize actions with policies. Never rely on hiding a button in React as access control.

How authentication works in Inertia

In a classic API + SPA setup the browser stores a token and sends it with every request. In Inertia the browser keeps a session cookie, exactly like a Blade application. The flow is:

  1. The React login form submits a POST request to /login with the email, password and CSRF token.
  2. Laravel validates the credentials with Auth::attempt().
  3. Laravel regenerates the session ID and redirects to the intended URL.
  4. The next Inertia visit includes the session cookie; HandleInertiaRequests shares the authenticated user as a prop.
  5. React reads usePage().props.auth.user and renders the authenticated layout.

Because Inertia uses the web middleware group, CSRF protection, session encryption and cookie settings work without extra configuration.

  • ## Option A: Laravel React starter kit (recommended)

The fastest path is the official React starter kit, which ships with Inertia, authentication and a modern UI.

laravel new my-app --react
cd my-app
composer install
npm install
npm run dev

The starter kit includes

  • login, registration and logout;
  • password reset and email verification;
  • profile management;
  • a persistent authenticated layout;
  • TypeScript types for shared props.

Use it as the baseline and replace the UI with your brand. Do not rebuild authentication from scratch unless you have a specific requirement the starter kit does not cover.

  • ## Option B: manual authentication in an existing app

If you already have a Laravel application, add authentication without replacing the frontend.

1. Create the auth controller

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;

class AuthenticatedSessionController extends Controller
{
    public function create()
    {
        return Inertia::render('Auth/Login');
    }

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

        if (! Auth::attempt($credentials, $request->boolean('remember'))) {
            throw ValidationException::withMessages([
                'email' => __('auth.failed'),
            ]);
        }

        $request->session()->regenerate();

        return redirect()->intended(route('dashboard'));
    }

    public function destroy(Request $request)
    {
        Auth::logout();

        $request->session()->invalidate();
        $request->session()->regenerateToken();

        return redirect('/');
    }
}

2. Register the routes

use App\Http\Controllers\Auth\AuthenticatedSessionController;

Route::middleware('guest')->group(function () {
    Route::get('/login', [AuthenticatedSessionController::class, 'create'])->name('login');
    Route::post('/login', [AuthenticatedSessionController::class, 'store']);
});

Route::post('/logout', [AuthenticatedSessionController::class, 'destroy'])
    ->middleware('auth')
    ->name('logout');

3. Create the React login page

import { useForm } from '@inertiajs/react';

export default function Login() {
    const { data, setData, post, processing, errors, reset } = useForm({
        email: '',
        password: '',
        remember: false,
    });

    function submit(event) {
        event.preventDefault();
        post('/login', {
            onFinish: () => reset('password'),
        });
    }

    return (
        <form onSubmit={submit}>
            <input
                type="email"
                value={data.email}
                onChange={(e) => setData('email', e.target.value)}
                autoComplete="username"
            />
            {errors.email && <p>{errors.email}</p>}

            <input
                type="password"
                value={data.password}
                onChange={(e) => setData('password', e.target.value)}
                autoComplete="current-password"
            />
            {errors.password && <p>{errors.password}</p>}

            <label>
                <input
                    type="checkbox"
                    checked={data.remember}
                    onChange={(e) => setData('remember', e.target.checked)}
                />
                Remember me
            </label>

            <button disabled={processing}>Log in</button>
        </form>
    );
}

4. Share the authenticated user

app/Http/Middleware/HandleInertiaRequests.php

public function share(Request $request): array
{
    return [
        ...parent::share($request),
        'auth' => [
            'user' => $request->user()?->only('id', 'name', 'email'),
        ],
        'flash' => [
            'success' => fn () => $request->session()->get('success'),
            'error' => fn () => $request->session()->get('error'),
        ],
    ];
}

5. Protect routes and render the layout

Route::middleware('auth')->group(function () {
    Route::get('/dashboard', fn () => Inertia::render('Dashboard'))->name('dashboard');
    Route::resource('orders', OrderController::class);
});
export default function AuthenticatedLayout({ children }) {
    const { auth } = usePage().props;

    return (
        <div>
            <header>
                <span>{auth.user.name}</span>
                <Link href="/logout" method="post" as="button">Log out</Link>
            </header>
            <main>{children}</main>
        </div>
    );
}

Registration, password reset and email verification

Registration follows the same pattern: validate the input, create the user, log them in and redirect.

public function store(Request $request)
{
    $data = $request->validate([
        'name' => ['required', 'string', 'max:255'],
        'email' => ['required', 'email', 'max:255', 'unique:users,email'],
        'password' => ['required', 'confirmed', Rules\Password::defaults()],
    ]);

    $user = User::create($data);

    Auth::login($user);

    return redirect()->route('dashboard');
}

For password reset and email verification, use Laravel's built-in notifications and the starter kit's controllers. The React pages are forms that post to the Laravel routes; there is no special Inertia integration required.

Tip: Keep the password reset flow on the server. Do not build a custom token system in React. Laravel's signed URLs, throttling and notifications are already audited and tested.

Authorization

Authentication answers "who are you"; authorization answers "what can you do". In Inertia, authorization must happen on the server.

Policies

public function update(UpdateOrderRequest $request, Order $order)
{
    $this->authorize('update', $order);

    $order->update($request->validated());

    return redirect()->route('orders.show', $order);
}

Shared abilities

Expose only the abilities the UI needs

'auth' => [
    'user' => $request->user()?->only('id', 'name', 'email'),
    'can' => [
        'create_orders' => $request->user()?->can('create', Order::class),
        'manage_billing' => $request->user()?->can('manageBilling', Team::class),
    ],
],

Use them to hide actions, but keep the server-side check. A hidden button is a UX improvement, not a security boundary.

Middleware

Use can middleware for route-level checks

Route::put('/orders/{order}', [OrderController::class, 'update'])
    ->middleware('can:update,order');

Sanctum or session?

Scenario Recommended auth
Same-domain Inertia web app Laravel session
Mobile app Sanctum API tokens
Third-party API clients Sanctum tokens or OAuth
Multiple frontends on different domains Sanctum SPA authentication with CORS

Inertia uses the session guard. Sanctum is for the moment you extract an API for a second client. Do not add Sanctum to an Inertia-only app "just in case" — it adds configuration and attack surface without a consumer.

Common mistakes

  1. Storing the user in localStorage. The session cookie is enough; localStorage is vulnerable to XSS.
  2. Checking permissions only in React. Always authorize on the server.
  3. Forgetting session()->regenerate() after login. It prevents session fixation.
  4. Not invalidating the session on logout. Call invalidate() and regenerateToken().
  5. Using the API guard for the web client. Inertia expects the web guard and session middleware.
  6. Sharing too much user data. Share only the fields the UI needs.
  7. Skipping email verification on sensitive routes. Use the verified middleware where it matters.
  8. No rate limiting on login. Add throttle to slow brute-force attempts.

FAQ

Does Inertia.js need Sanctum?

No. Inertia uses Laravel's session authentication. Sanctum is only needed when you add a mobile app or a third-party API.

How do I get the authenticated user in React?

Share it in HandleInertiaRequests and read usePage().props.auth.user.

How do I protect a route?

Use the auth middleware in Laravel. The React side never decides whether a route is protected.

How do I handle 401 responses?

Inertia visits to protected routes are redirected to the login page by Laravel's auth middleware. For standalone requests, handle 401 in useHttp or fetch.

Can I use OAuth or social login?

Yes. Use Laravel Socialite on the server and redirect back to an Inertia page. The frontend only renders the provider buttons.

How do I implement "remember me"?

Pass the boolean to Auth::attempt($credentials, $remember). Laravel sets the remember cookie.

How do I log out?

Post to a Laravel route that calls Auth::logout(), invalidates the session and regenerates the CSRF token, then redirects.

Sources


Building an authenticated SaaS on Laravel and React? Check our Laravel development services or hire a Laravel developer.

Read more: Inertia.js with Laravel and React, Sanctum SPA vs Inertia session auth, Inertia.js forms and validation and testing Inertia.js applications.

KS

Krzysztof Słonina

Full stack developer and owner of Inoventis Solutions (informatix). Since 2009 he has built Laravel/PHP web applications, e-commerce integrations and process automations — including OneCRMApp and FamilyTimelineApp, both running on Laravel, React and Inertia.js.

About the author

Related posts