Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

boyjarv's avatar

Laravel Sanctum - Cookies not being set

I have followed the instructions and set it all up https://laravel.com/docs/9.x/sanctum#how-it-works

POSTMAN is setting cookie in the headers but it's not actually being set?! I have added

axios.defaults.withCredentials = true;

to my vue app

Cookies are just not getting set?! Please help

0 likes
29 replies
vincent15000's avatar

Wow it looks like I'm not the only having problems to configure correctly sanctum to be working fine with VueJS / axios.

But here your problem is with Postman, isn't it ?

Have you checked if the cookie is set in the browser ?

2 likes
boyjarv's avatar

so initially it was working ok with POSTMAN, browser. has never worked

1 like
vincent15000's avatar

@boyjarv Ok so you are trying to configure it to have it working with a browser.

I had to set correctly the domains in the .env file.

SESSION_DOMAIN and SANCTUM_STATEFUL_DOMAINS

What is your code to initiate the login from the front ?

boyjarv's avatar

this is my Login method where the cookie should be set:

public function login(Request $request) {
        if (!\Auth::attempt($request->only('email', 'password'))) {
            return response([
                'error' => 'invalid credentials'
            ], Response::HTTP_UNAUTHORIZED);
        }

        $user = \Auth::user();

        $adminLogin = $request->path() === 'api/admin/login';

        if($adminLogin && !$user->is_admin) {
            return response([
                'error' => 'Access Denied!'
            ], Response::HTTP_UNAUTHORIZED);
        }

        $scope = $adminLogin ? 'admin' : 'ambassador';
        $jwt = $user->createToken('token', [$scope])->plainTextToken;


        $cookie = \Cookie::make('jwt', $jwt, 60*24); //1 day
        return response([
            'message'=> 'success'
        ])->withCookie($cookie);
    }
1 like
vincent15000's avatar

@boyjarv You have customized the authentication system, are you sure to respect the Laravel authentication system ?

I use Fortify to manage the authentication, I've never tried to write my own authentication system.

And I see that you are creating a token for the user. Why do you need it ?

When I tried to understand how Sanctum is working, I also created a token, but it is not necessary because Sanctum does it for you. Unless you really need one.

How are you calling your login API ? I mean the VueJS / React / ... code ?

boyjarv's avatar

in my Vue app main.ts


import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import vuetify from './plugins/vuetify'
import axios from 'axios'

axios.defaults.baseURL = 'http://laravel-ambassador.test/api/admin/';
axios.defaults.withCredentials = true;

Vue.config.productionTip = false

new Vue({
  router,
  store,
  vuetify,
  render: h => h(App)
}).$mount('#app')

config/session.php

domain' => env('SESSION_DOMAIN', env('APP_URL')),

config/sanctum.php

'stateful' => explode(',', env(
        'SANCTUM_STATEFUL_DOMAINS',
        'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1,laravel-ambassador.test'
    )),

.env

SESSION_DRIVER=file
SESSION_SECURE_COOKIE=false
SESSION_DOMAIN=laravel-ambassador.test
SANCTUM_STATEFUL_DOMAINS=laravel-ambassador.test,http://localhost:8080
1 like
vincent15000's avatar

@boyjarv I'm not sure because I'm yet learning around Sanctum. I have problem too ;).

Try this.

SESSION_DOMAIN=laravel-ambassador.test,localhost:8080
SANCTUM_STATEFUL_DOMAINS=laravel-ambassador.test,localhost:8080

You don't need to add the domain route in the sanctum configuration file, you already add it via the .env file.

vincent15000's avatar

@boyjarv I didn't notice first, but the session driver has to be cookie and not file.

SESSION_DRIVER=cookie

But for me it doesn't work better, even with cookie it doesn't work.

boyjarv's avatar

and my Vue login file:

<template>
  <main class="form-signin w-100 m-auto">
    <form @submit.prevent="submit">
      <h1 class="h3 mb-3 fw-normal">Please sign in</h1>

      <div class="form-floating">
        <input
          v-model="email"
          type="email"
          class="form-control"
          placeholder="[email protected]"
        />
        <label>Email address</label>
      </div>
      <div class="form-floating">
        <input
          v-model="password"
          type="password"
          class="form-control"
          placeholder="Password"
        />
        <label>Password</label>
      </div>
      <button class="w-100 btn btn-lg btn-primary" type="submit">
        Sign in
      </button>
    </form>
  </main>
</template>

<script>
import axios from 'axios'

export default {
  name: "Login",
  data() {
    return {
        email: '',
        password: ''
    }
  },
  methods: {
    async submit() {
        await axios.post('login', {
            email: this.email,
            password: this.password,
        }, {withCredentials: true});
    
        await this.$router.push('/');
    }
  }
};
</script>

<style scoped>

.form-signin {
  max-width: 330px;
  padding: 15px;
}

.form-signin .form-floating:focus-within {
  z-index: 2;
}

.form-signin input[type="email"] {
  margin-bottom: -1px;
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
}

.form-signin input[type="password"] {
  margin-bottom: 10px;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}
</style>
1 like
Ganesh Adhikari's avatar

@vincent15000 I have 419 error and i am not being able to solve it what ever i do. I am using react front end and laravel breeze api authentication system.

1 like
DhPandya's avatar

@Ganesh Adhikari Create a new thread instead adding reply on older threads. This helps moderator to answer quickly.

1 like
boyjarv's avatar

no a 401 because my cookie is not being set in the browser and therefore I'm unauthorised

1 like
vincent15000's avatar

@boyjarv Can you try this. It just worked for me.

For me the front and the back are on the same domain, but on different subdomains.

In this case, the SESSION_DOMAIN has to be defined with a dot (as if there were a wildcard).

SESSION_DOMAIN=.mydomain.com
1 like
boyjarv's avatar

would it be something to do with my CORS blocker or the fact I am using Laravel valet?

1 like
vincent15000's avatar

@boyjarv For Laravel Valet, I don't know. Something to do with the CORS, I don't think so, you would have an explicit error in the network development tools on the browser.

vincent15000's avatar

Do you really need to customize the authentication system ?

vincent15000's avatar

@boyjarv Ok so you don't really need to customize the authentication system.

I think that I have understood how to do. Don't overwrite the login function in your controller. Just use the Laravel authentication system. I use Fortify and it's just magic for me. But you can also use another package like Breeze for example.

Once you have installed the authentication system, you can test it adding a simple form in your back, so you are sure it works.

Then you have to install Sanctum (unless you are using Laravel 9 where it is already included).

All is very simple, but in fact I took 2 weeks to solve my different issues (fortunately I have sleeped and worked on other projects at the same time) ;).

Once you have sanctum installed, you just have to set it up correctly.

// sanctum.php
// nothing to change

// cors.php
	// all routes for which you want that Laravel don't block with CORS error 
    'paths' => ['api/*', 'sanctum/csrf-cookie', 'login', 'logout'],
	...
	'supports_credentials' => true,

// session.php
// nothing to change

// .env
SESSION_DRIVER=cookie
SESSION_DOMAIN=.yourdomain.com // notice the dot
SANCTUM_STATEFUL_DOMAINS=subdomain_that_access_the_api.yourdomain.com // frontend URL

// bootstrap.js

window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
window.axios.defaults.withCredentials = true;

Then in the front end code, you have to configure axios.

const api = axios.create({
	baseURL: 'http://your_api_subdomain.yourdomain.com',
	withCredentials: true
})

And you can use api to access your API.

async login(user) {
  await api.get('/sanctum/csrf-cookie') // first you retrieve the CSRF token
  await api.post('/login', { email: user.email, password: user.password }) // then you login via the login route
  return // what you want here ;)
}

Then you can access any other API route

api.get('/api/my_super_route')

I hope I have not forgotten anything ;).

vincent15000's avatar

@boyjarv By default this route is at the root of your domain.

http://laravel-ambassador.test/sanctum/csrf-cookie

You can find it by displaying the routes.

php artisan route:list

Please or to participate in this conversation.