amrnn90 / breeze-nuxt

An application / authentication starter kit frontend in Nuxt3 for Laravel Breeze.
MIT License
198 stars 33 forks source link

Duplicated XSRF TOKEN with custom subdomains #22

Closed carlosvaldesweb closed 11 months ago

carlosvaldesweb commented 11 months ago

Hello, i checking that when i use custom subdomain with laravel valet like api.domain.test and webapp.domain.test, the XSRF TOKEN is duplicated with different domain, causing 419 errors in login page and other requests.

Reproduction:

.env laravel

SANCTUM_STATEFUL_DOMAINS=webapp.domain.test
SESSION_DOMAIN=.domain.test

Nuxt: I have simple component with useAsyncData, and is the same with useLarafetch, and when i make call, new XSRF TOKEN is issued in my cookies but with subdomain, so, i have two XSRF TOKENS, one with .domain.test and one with webapp.domain.test. Also i'm checking that it only succeed when i use a layout

page1.vue

<script lang="ts" setup>
const { data: uniqueId } = await useAsyncData("uniqueId", () => {
  return $larafetch("/user/unique-id");
});
</script>

<template>
  <div>
      <div>Hello</div>
<NuxtLink to="/page2">Page 2</NuxtLink>
  </div>
</template>

Also, to reproduce, you need to add page1 and page 2, and move between pages with NuxtLink

page2.vue

<script lang="ts" setup>
</script>

<template>
  <div>
      <div>Hello from page 2</div>
<NuxtLink to="/page1">Page 1</NuxtLink>
  </div>
</template>

After move between pages 2 o 4 times, check cookies and you should see two XSRF TOKENS

amrnn90 commented 11 months ago

I am not using valet, but with my current setup I am unable to reproduce this. FYI you do not need to set this SANCTUM_STATEFUL_DOMAINS=webapp.domain.test as Sanctum sets it up automatically based on your FRONTEND_URL env variable.

Anyway here is my setup and things are working as expected.

// frontend/.env

NUXT_PUBLIC_BACKEND_URL=http://api.breeze.localhost
NUXT_PUBLIC_FRONTEND_URL=http://webapp.breeze.localhost

// backend/.env

...
APP_URL=http://api.breeze.localhost
FRONTEND_URL=http://webapp.breeze.localhost
SESSION_DOMAIN=.breeze.localhost
...

I am also using caddy as a reverse proxy. // Caddyfile

http://webapp.breeze.localhost, https://webapp.breeze.localhost {
    reverse_proxy localhost:3000
}

http://api.breeze.localhost, https://api.breeze.localhost {
    reverse_proxy localhost:8000
}

Finally I have this in my OS /etc/hosts file:

127.0.0.1 webapp.breeze.localhost
::1       webapp.breeze.localhost
127.0.0.1 api.breeze.localhost
::1       api.breeze.localhost

https://github.com/amrnn90/breeze-nuxt/assets/38134195/bfccdf7f-2077-43b2-83ac-0e8b44fa2641

carlosvaldesweb commented 11 months ago

Thanks for your answer, to reproduce correctly, you need to make an api request to your backend to get Data. In my case i've created a fresh project with nuxt breeze and two files, page1 and page 2.

Page1:

<template>
  <div>
    <div class="text-xl">Hello from page 1</div>
    <NuxtLink to="/page2">Go to Page 2</NuxtLink>
  </div>
</template>

<script lang="ts" setup></script>

<style></style>

Page2:

<template>
  <div>
    <div class="text-xl">Hello from page 2</div>
    <NuxtLink to="/page1">Go to Page1</NuxtLink>
  </div>
</template>

<script lang="ts" setup>
const { data } = useAsyncData("uniqueId", () => {
  return $larafetch("/user/unique-id");
});

Notice that when i comment the lines with the useAsyncData call, it doesnt create duplicated XSRF Token, and when i make the request to backend, it duplicate the XRSF

Laravel:

APP_URL=http://api.breeze.test
FRONTEND_URL=http://app.breeze.test
SESSION_DOMAIN=.breeze.test

Unique Id method in laravel, only for demonstration purposes:

public function uniqueId(Request $request)
    {
        $user = $request->user();
        $uniqueId = Str::random(8);
        return $uniqueId;
    }

https://github.com/amrnn90/breeze-nuxt/assets/32969705/a5ae9407-cd97-4386-b7ac-9069886897d3

amrnn90 commented 11 months ago

In my demo page1.vue had a useAsyncData() call which provides that {"id": 1} value you see on the page. I would suggest using localhost:3000 and localhost:8000 for development if possible to avoid running into such weird issues.

carlosvaldesweb commented 11 months ago

I've tried with localhost:3000 and localhost:8000 and it works correctly. I think that is problem with laravel valet config, maybe the proxy is not working correctly. Thanks for your help @amrnn90