skip to Main Content

I’m building a Laravel API with Sanctum authentication and testing it with Postman but all I can get is a 401 Unauthorized response. The project is a clear Laravel 10 project with Sanctum. I’ve installed it, migrated it’s tables and executed the default DatabaseSeeder.

As I want to this API to work as a back-end for multiple front-end in different applications, I want to work with Sanctum Tokens(Is there a better option?). I’ve copied the token creation route from this doc(just changed device_name property name to token_name, didn’t touched anything more) into routes/api.php:

Route::post('/sanctum/token', function (Request $request) {
    $request->validate([
        'email' => 'required|email',
        'password' => 'required',
        'token_name' => 'required',
    ]);
 
    $user = User::where('email', $request->email)->first();
 
    if (!$user || !Hash::check($request->password, $user->password)) {
        throw ValidationException::withMessages([
            'email' => ['The provided credentials are incorrect.'],
        ]);
    }
 
    return $user->createToken($request->token_name)->plainTextToken;
});

I’ve changed the following points event though I don’t know if it’s needed as Laravel docs don’t mention them(found these on web searches):

  • config/cors.php (changed default value false to true):

     'supports_credentials' => true,
    
  • Http/Kernel.php (uncommented following line):

     LaravelSanctumHttpMiddlewareEnsureFrontendRequestsAreStateful::class,
    

This is my Postman request:

enter image description here

I’m not sure how to overcome this problem. I don’t want to start any front-end app without making sure API routes works.

2

Answers


  1. Personally, if you plan on using multiple frontend clients for the API, I’d use Passport instead.

    But, if you want to use Sanctum, a few things to check:

    1. Make sure you’ve updated app->config->auth.php file to update the guard used for each route. For example, I use sanctum for Web auth, passport for API based auth:

      ‘guards’ => [
      ‘web’ => [
      ‘driver’ => ‘session’,
      ‘provider’ => ‘users’,
      ],
      ‘api’ => [
      ‘driver’ => ‘passport’,
      ‘provider’ => ‘users’,
      ],
      ],

    2. Make sure your User model / controller has sanctum auth references where appropriate. For instance, my User model uses (using passport but same concept):

    use IlluminateFoundationAuthUser as Authenticatable;
    use LaravelPassportHasApiTokens;

    1. For testing with Sanctum in Postman, you may also need to comment out this line in your app->http->kernals file. AppHttpMiddlewareVerifyCsrfToken::class
      However, you should make sure you enable this middleware before going live with a client UI as it’s a significant security vulnerability.

    Those are the three main items I’ve run into that cause issues if not setup properly. Also, when you make updates like this, make sure to run php artisan cache:clear and php artisan config:clear just to be safe you’re not running into caching issues.

    Login or Signup to reply.
  2. In your Postman request, you are targeting a web route /sanctum/token , while you mplemented the authentication route in your api routes that should be /api/sanctum/token

    Its weird that you are getting 401 response, when you should have gotten 404 response.

    Other than that, I don’t see any problem with your implemention, once you use the /api/sanctum/token in your postman request with correct headers (Accept, Content-Type) you should get the proper response based on your route configuration either invalid credintials or plain text token which you can then store somewhere and add it on Authorization header for sub-sequent request.

    So, first issue a plain text token via user authentication

    POST https://mydomain.me/api/sanctum/token HTTP/1.1
    Accept: application/json
    Content-Type: application/json
    
    {
        "email": "[email protected]",
        "password": "something-password",
        "token_name": "test"
    }
    

    Once sucessful, saved the plaintext token, then use it on sub-sequent request protect by auth sanctum middleware e.i.
    you have this api route

    Route::group(['middleware' => 'auth:sanctum'], function () {
        Route::get('/whatever-routes-protected-by-auth-sanctum', [MyDuhController::class, 'duh'])->name('duh');
    });
    

    then your request

    GET https://mydomain.me/api/whatever-routes-protected-by-auth-sanctum HTTP/1.1
    Accept: application/json
    Content-Type: application/json
    Authorization: Bearer PLAIN_TEXT_TOKEN
    
    {
        "hey": "Yes",
        "hi": "hello"
    }
    

    In summry, always append /api in your base URL if you are targetting an API route

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search