The Right Way to Implement Laravel Sanctum Mobile Authentication

📖 2 minutes read

Laravel’s Sanctum documentation shows the exact pattern for mobile app authentication. Here’s the production-ready implementation:

The Login Endpoint

use App\Models\Account;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;

Route::post('/auth/token', function (Request $request) {
    $request->validate([
        'email' => 'required|email',
        'password' => 'required',
        'device_name' => 'required',
    ]);

    $account = Account::where('email', $request->email)->first();

    if (! $account || ! Hash::check($request->password, $account->password)) {
        throw ValidationException::withMessages([
            'email' => ['The provided credentials are incorrect.'],
        ]);
    }

    return $account->createToken($request->device_name)->plainTextToken;
});

Why This Pattern Works

  1. Single query with Hash::check() – Prevents timing attacks by checking both user existence and password in one validation
  2. ValidationException for API errors – Returns proper JSON:API error format automatically
  3. Device name tracking – The device_name field lets users manage their active sessions (“iPhone 14”, “Work Laptop”, etc.)
  4. plainTextToken – Critical: This is the ONLY time you can retrieve the token. Store it in the mobile app immediately.

Protected Routes

Route::get('/profile', function (Request $request) {
    return $request->user();
})->middleware('auth:sanctum');

Mobile client sends:

Authorization: Bearer {plainTextToken}

Logout Implementation

Route::post('/auth/logout', function (Request $request) {
    // Revoke current device token only
    $request->user()->currentAccessToken()->delete();
    
    return response()->json(['message' => 'Logged out successfully']);
})->middleware('auth:sanctum');

Daryle De Silva

VP of Technology

11+ years building and scaling web applications. Writing about what I learn in the trenches.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *