sanctum: CSRF token mismatch and Unauthenticated

I can’t get it to work with Nuxt in the front-end, firstly I got the **419 ** error number when I tried to access to /login which is a CSRF token issue, I disabled the **CSRF ** token by adding wildcard access in VerifyCsrfToken Middleware:

protected $except = [
        '/*',
    ];

I passed the login part with that, but I faced another one which is 401 ~ Unauthenticated: Although I’m in the stateful mode

Laravel app is running on: http://localhost:8000/ Nuxt app is running on: http://localhost:3000/

I think, there’s an issue on ```EnsureFrontendRequestsAreStateful`` My Request using Axios as Nuxt Module:

// I get the cookie [I'm using api as a prefix]
this.$axios.$get('http://localhost:8000/api/csrf-cookie')
// I pass the login
.then(res => {
  this.$axios.$post('http://localhost:8000/login',
  {
    email: this.email,
    password: this.password
  }) 
  // I fail here with 401
  .then( data => {
    this.$axios.$get('http://localhost:8000/api/posts')
    .then( posts => console.log(posts))
  })
})

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 34 (2 by maintainers)

Most upvoted comments

I find another reason. If you use Api Token rather than SPA. Your app/Http/Kernel.php file should look like this

'api' => [
//            useless for api token
//            EnsureFrontendRequestsAreStateful::class,
       'throttle:60,1',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
 ],

After trying all of the possible solutions, there is what I come up with, and a bit long checklist for future devs experiencing 401 Unauthorized and 419 Token mismatch erros.

Firstly, we should set both apps on same domain. We can use localhost for both, or if we use valet then we can configure reverse proxy for our nuxt app. If you prefer to use localhost, then launch backend app with php artisan serve and your backend will be available at localhost:8000 and frontend at localhost:3000.

I will go with valet, so backend will be blog.test and frontend at front.blog.test

Valet setup

Create blog.conf file at ~/.config/valet/Nginx/

map $sent_http_content_type $expires {
    "text/html"                 epoch;
    "text/html; charset=utf-8"  epoch;
    default                     off;
}

server {
    listen          127.0.0.1:80;
    server_name     front.blog.test;    # setup your domain here

    gzip            on;
    gzip_types      text/plain application/xml text/css application/javascript;
    gzip_min_length 1000;

    location / {
        expires $expires;

        proxy_redirect                      off;
        proxy_set_header Host               $host;
        proxy_set_header X-Real-IP          $remote_addr;
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_read_timeout                  1m;
        proxy_connect_timeout               1m;
        proxy_pass                          http://127.0.0.1:3000; # set the adress of the Node.js instance here
    }
}

Backend

/config/auth.php In my app, I moved from JWT to Sanctum. So need to recheck auth file. If you created fresh app then skip this.

'defaults' => [
    'guard' => 'web',
    'passwords' => 'users',
],

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],
    'api' => [
        'driver' => 'token',
        'provider' => 'users',
        'hash' => false,
    ],
],

/config/sanctum.php

'stateful' => [
    'front.blog.test'
],

/config/cors.php

'paths' => [
    'sanctum/csrf-cookie',
    'login',
    'api/*'
],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,

/config/session.php

'driver' => 'cookie',
'domain' => '.blog.test',
'same_site' => 'lax',

/app/Http/Kernel.php Make sure you have cors

protected $middleware = [
    ...
    \Fruitcake\Cors\HandleCors::class,
];

/routes/api.php Make sure you use auth:sanctum middleware

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

Frontend

nuxt.config.js

modules: [
  '@nuxtjs/axios',
  '@nuxtjs/auth'
],

axios: {
  baseURL: "http://blog.test",
  credentials: true   // Attention, credentials not withCredentials
},

auth: {
  redirect: {
    login: '/login',
    logout: '/',
    callback: '/login',
    home: '/'
  },
  strategies: {
    local: {
      endpoints: {
        login: { url: '/login', method: 'post', propertyName: false },
        user: { url: '/api/user', method: 'get', propertyName: false }
      },
      tokenRequired: false,
      tokenType: false
    }
  },
  localStorage: false
},

Using Laravel Sanctum/Airlock with NuxtJS Authentication in Nuxt.js using Laravel Sanctum

@taylorotwell Can you support me

POST: /api/curent-user: message: "Unauthenticated."


My config: SESSION_DRIVER=cookie

SESSION_DOMAIN=.codeky.local

AIRLOCK_STATEFUL_DOMAINS=admin.codeky.local

'supports_credentials' => true

'paths' => ['api/*', 'login'],

DeepinScreenshot_select-area_20200320182335 DeepinScreenshot_select-area_20200320182318 DeepinScreenshot_select-area_20200320182344

If anyone is facing CSRF token mismatch issue, then please try checking if SANCTUM_STATEFUL_DOMAINS= is set in .env

When SANCTUM_STATEFUL_DOMAINS is not present in ENV then it throws CSRF token mismatch error.

Hope it helps someone. 😃

I got to this point yesterday and part of it was CORS. However if you are to the point where you are getting a valid 401 response, try changing the SESSION_DRIVER to cookie (mentioned in #11). A combination of correct CORS, SESSION_DOMAIN, and SESSION_DRIVER got this resolved.

I managed to get this working with the NuxtJS auth module as well and pushed the code to help out.

Here’s my NuxtJS frontend: https://github.com/serversideup/airlock-nuxt-frontend Here’s my Laravel Airlock Backend: https://github.com/serversideup/airlock-laravel-api

I wrote a quick guide to getting them working together focused mainly on NuxtJS frontend with their first class auth module: https://serversideup.net/using-laravel-airlock-with-nuxtjs/.

If you guys need any help, let me know!

I found that I needed the following middleware to get any form of working CSRF with the current instructions as written.

Don't try this at home

Reading the token from the cookie header like the middleware above does will not protect against CSRF since that cookie is sent along with the request regardless of where it came from, defeating the purpose of CSRF protection entirely.

In order for this to work properly the SPA would need to send back the value of the XSRF-TOKEN cookie under the request header X-XSRF-TOKEN, which currently does not seem to be documented here, but this is how Laravel resolves encrypted CSRF cookies.

No. Airlock does not require you to put everything in the same app. I’ve tested it fine with Vue CLI. These are all CORS issues.

it may seem obvious, but as developers we learn from mistakes to improve. like @ToNyRANDRIAMANANTSOA mentioned, i had a smiliar issue where the frontend client was pointing to http://127.0.0.1:8000 rather than http://localhost:8000 where my SESSION_DOMAIN=localhost and SANCTUM_STATEFUL_DOMAINS=localhost:8086 (quasar). thank you !

I’m not sure if this is relevant to your particular case, but I encountered a similar issue. I was receiving 419 while accessing /login straight after successful token request (sanctum/csrf-cookie). In my case the problem was that Auth::routes() were in web.php, rather than api.php. Moving the Auth::routes() to api.php fixed the issue to me.

I don’t think so, I used laravel-cors

Hello @danpastori , It’s not an Axios issue, I tried with vanilla JS using XHR, besides I disabled the CSRF on all routes and I got 401. I start to believe that Airlock assumes that the incoming requests are within Laravel application not another provider which is Vue/Nuxt in our case. So the SPA is just the front-end part that lives within Resources folder of Laravel App, and if we want to work with Nuxt, Vue-CLI or any front-end as a seperate app we should use API Tokens Not stateful

@alignwebs wow this actually worked. thanks

I had this problem with getting an “Unauthenticated” error (401) for subsequent requests after a successful login. In my case it was because I made some API requests in nuxtServerInit or in the created hook. Because of how Nuxt works, those requests are made from the server and not from the client. And I guess the appropriate headers is not included then by default. I found two different solutions.

Make sure the request is made only from the client by using:

if (process.browser) {
  // Make request
}

This can be used in the created hook, but won’t work in nuxtServerInit.

The other solution is to set proxyHeaders: true in the axios options. According to the docs:

In SSR context, this options sets client requests headers as default headers for the axios requests. This is useful for making requests which need cookie based auth on server side. This also helps making consistent requests in both SSR and Client Side code.

I hope this helps someone. I was banging my head for a while, before I figured out what was going on.

@taylorotwell @driesvints I think you would spare yourself a lot of support requests if you added a note about this trap in the docs. Many users seem to be stuck because of this, and think this is a problem with Sanctum, which it’s not. Nuxt and Laravel seems to be a popular combo, and it would be a shame if they gave up on using Sanctum because of this.

For my case, the cause of the CSRF token mismatch was that I have multiple host names (other than localhost) pointing to 127.0.0.1 set on my local machine, and reactscripts started the development server to the other hostname. Changing it back to localhost solved the issue, they should be on the same domain 😃

AIRLOCK_STATEFUL_DOMAINS=127.0.0.1 in the .env file works for me.