How can i handle both SPA and token based authentication with Laravel Sanctum

Viewed 2510

It's been several days now that I spend on Laravel Sanctum trying to figure out how I can set up my authentication system.

Context

I'm building a tickets web app for my company and for this i decided to build an API and a React frontend app that consumes the API. End-users of the app need an account to manage tickets so i create an user table in the database and create several routes for the API to create, delete and update users. To manage users api authentication, i decided to use Laravel Sanctum and his built-in SPA authentication system that is session based.

For that, i follow the guide and setup all the needs to ensure that the frontend is ready to work with laravel sanctum. Here my Kernel.php for the api middlewares :

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

And the routes in web.php to login / logout the user through Laravel Sanctum SPA authentication.

<?php
use App\Http\Controllers\UserController;
use Illuminate\Support\Facades\Route;

Route::post('/login', [UserController::class, 'login']);
Route::get('/logout', [UserController::class, 'logout']);

Problem

I have to build a non-web application, in particular a windows-service that needs to fetch data in a dabatase and use the /api/tickets endpoint of the API with POST method to create a new ticket with these data.

I know that this futur windows-service is not a front-end app so i can't use the SPA authentication system. Instead, i want to use tokens with Laravel Sanctum to authenticate the service.

My questions are :

  • How i can achieve this and seperate the users authentication and the service authentication.
  • As my api contains http://myapi.net/login et http://myapi.net/logout for end-users authentication, do i need to create something like api/auth/service route for sending and deleting token ?
  • Should i create a new table called service in my database or stay with user table ?
1 Answers

I am working in a project with a similar context. What I have done is establish user profiles based on the use they are allowed to make of the API. Use the Sanctum token abilities for this: https://laravel.com/docs/8.x/sanctum#token-abilities

  1. Ensure your User class extends Authenticable:
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}
  1. Create API routes and controller methods for your service profile authentication where you assign some type of special token abilities you need:
$token = $user->createToken('app-token', ['service'])->plainTextToken;

...where 'service' will be the ability that you will check. Return this token in the /login endpoint as API-KEY.

  1. On each service API path, verify authentication using the Sanctum middleware:
Route::middleware('auth:sanctum')->post('/updatesomething', 'something@update');
  1. Within the controller methods, verify the token abilities to prevent web users from making use of them or vice versa. Ideally you can create a new middleware with this logic to apply to these routes.
public function update(Request $request){
        if ($user->tokenCan('service')) {
        //do allowed actions to user profile 'service'
    }
}

In this way, you can now consume your API with a 'service' profile and authenticated for this purpose using the token received in /login in the following requests. You should include it in a header like 'Bearer Token'. Optionally you can create a logout method in your API and revoke the token when you see fit:

$user->tokens()->delete();
Related