Laravel 12 Sanctum Setup: User Sign-Up, Login, and Logout Made Simple

Author

Kritim Yantra

Apr 04, 2025

Laravel 12 Sanctum Setup: User Sign-Up, Login, and Logout Made Simple

Laravel Sanctum is like a Swiss Army knife for authentication in modern web apps. Whether you're building a single-page application (SPA), mobile app, or API, Sanctum handles authentication securely and elegantly. In this guide, we'll create a food delivery app to demonstrate user registration, login, and logout using Sanctum. No prior Sanctum experience required!


What We're Building

Imagine "Foodly," a food delivery service with:

  • A React frontend (SPA) at localhost:3000
  • A Laravel backend API at localhost:8000
  • Mobile apps (iOS/Android) using the same API

Step 1: Install & Configure Sanctum

Install Sanctum

php artisan install:api

Configure Sanctum

In config/sanctum.php:

'stateful' => [
    'localhost:3000', // Your SPA domain
    'foodly-app://' // Mobile app deep link
],

Update CORS Config

In config/cors.php:

'supports_credentials' => true,

Add Middleware

In bootstrap/app.php:

->withMiddleware(function (Middleware $middleware) {
    $middleware->statefulApi(); // Enable SPA auth
})

Step 2: User Registration

Create Registration Route

// routes/api.php
Route::post('/register', [AuthController::class, 'register']);

AuthController Method

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

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

    return response()->json(['message' => 'Registration successful!'], 201);
}

Example Registration Request (Postman):

POST /api/register
{
    "name": "Foodie User",
    "email": "user@foodly.com",
    "password": "secret123",
    "password_confirmation": "secret123"
}

Step 3: User Login

For Web (SPA Authentication)

1. Initialize CSRF Protection (React Example):

// LoginComponent.jsx
useEffect(() => {
    axios.get('http://localhost:8000/sanctum/csrf-cookie');
}, []);

2. Login Route

// routes/api.php
Route::post('/login', [AuthController::class, 'login']);

3. Login Method

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

    if (Auth::attempt($credentials)) {
        return response()->json(['user' => Auth::user()]);
    }

    return response()->json(['error' => 'Invalid credentials'], 401);
}

React Login Form:

const handleLogin = async () => {
    await axios.post('/login', {
        email: 'user@foodly.com',
        password: 'secret123'
    });
    
    // Subsequent requests automatically include session cookies
    const profile = await axios.get('/api/profile');
};

For Mobile Apps (API Tokens)

1. Token Generation Endpoint

// routes/api.php
Route::post('/mobile/login', [AuthController::class, 'mobileLogin']);

2. Mobile Login Logic

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

    $user = User::where('email', $request->email)->first();

    if (!$user || !Hash::check($request->password, $user->password)) {
        return response()->json(['error' => 'Invalid credentials'], 401);
    }

    return response()->json([
        'token' => $user->createToken($request->device_name)->plainTextToken
    ]);
}

Mobile Usage Example:

// Flutter API call
var response = await http.post(
  Uri.parse('http://localhost:8000/api/mobile/login'),
  body: {
    'email': 'user@foodly.com',
    'password': 'secret123',
    'device_name': 'Pixel 6',
  },
);

String token = response.body['token'];

Step 4: Protecting Routes

API Endpoint Protection

// routes/api.php
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/profile', function () {
        return auth()->user();
    });

    Route::post('/orders', [OrderController::class, 'store']);
});

Accessing Protected Routes

Web (Automatic Cookie Auth):

axios.get('/api/profile') // Cookies automatically included

Mobile (Bearer Token):

http.get(
  Uri.parse('http://localhost:8000/api/profile'),
  headers: {'Authorization': 'Bearer $token'},
);

Step 5: Logout Implementation

Web Logout (Session)

// routes/api.php
Route::post('/logout', [AuthController::class, 'logout']);
public function logout(Request $request)
{
    Auth::guard('web')->logout();
    $request->session()->invalidate();
    return response()->json(['message' => 'Logged out']);
}

Mobile Logout (Token Revocation)

public function mobileLogout(Request $request)
{
    $request->user()->currentAccessToken()->delete();
    return response()->json(['message' => 'Token revoked']);
}

Best Practices & Pro Tips

  1. Token Expiration: Add expiration to mobile tokens
// config/sanctum.php
'expiration' => 525600, // 1 year in minutes
  1. Token Scopes: Restrict token capabilities
$token = $user->createToken('pos-terminal', ['orders:create']);
  1. Regular Cleanup: Prune expired tokens
php artisan sanctum:prune-expired
  1. Secure Cookies: For SPAs, ensure SameSite and Secure flags
SESSION_SECURE_COOKIE=true
SESSION_SAME_SITE=lax

Testing Your Implementation

Web Flow Test:

  1. Register new user
  2. Login with credentials
  3. Access /api/profile
  4. Create test order
  5. Logout
  6. Verify profile access denied

Mobile Flow Test:

  1. Get token via /mobile/login
  2. Access profile with token
  3. Revoke token via /mobile/logout
  4. Verify token no longer works

When to Use Which Method?

Scenario Authentication Method
Same-domain SPA Session Cookies
Mobile Apps API Tokens
Third-party APIs Tokens with Scopes

By following this guide, you've created a robust authentication system for multiple client types. Sanctum's dual approach ensures your web users get seamless cookie-based auth while mobile apps use secure tokens. Remember to always validate user input and implement rate limiting in production!

Ready to take it further? Explore Sanctum's channel authentication for real-time features or implement OAuth2 for third-party integrations!

Comments

No comments yet. Be the first to comment!

Please log in to post a comment:

Sign in with Google

Related Posts

Laravel 12 Roles and Permissions Setup: Complete Guide
Kritim Yantra Kritim Yantra
Feb 28, 2025
Complete Laravel 12 CRUD Guide: Using Laravel UI, Bootstrap & Blade
Kritim Yantra Kritim Yantra
Mar 09, 2025