4
votes

Overview

I have a Laravel powered api locally hosted at http://tenant.api.hydrogen.local and an Angular 9.2 SPA which is being served on http://localhost:8100. I recently installed Laravel Sanctum for authentication and followed instructions for SPA's listed in the docs but the CSRF token is not attached to requests from the SPA and I therefore receive a CSRF token mismatch error.

As instructed I make an initial call to //abc.api.hydrogen.local/sanctum/csrf before subsequently attempting to login in:

this.http.get('sanctum/csrf-cookie')
    .pipe(
        switchMap(result => this.http.post('auth/login', {'email': email, 'password': password}))
    );

Note: I have an interceptor that prepends the request url with the api url '//abc.api.hydrogen.local/' e.g. 'sanctum/csrf-cookie' will become '//abc.api.hydrogen.local/sanctum/csrf-cookie'

The response from sanctum/csrf-cookie is returned with the expected headers:

Access-Control-Allow-Credentials: true
Set-Cookie: XSRF-TOKEN=eyJpdiI6Ilc3UkRLR1BSZ29TWVh3ZWZEQ3Y4aGc9PSIsInZhbHVlIjoiRUZBZXNFWTlZbWo5QWhIeWsrRmpjNUZVWkExSGtaT1hzUTVnSXpoaGQ4c3dFc2VLNjZsUHlUVWFmbG1uVVdKZSIsIm1hYyI6ImU1ZTAxNGFmMjAwNWRiMDhiODFjMGZhYTljYmU1NmRjYTUzYTNmNDJjNWM3YmQyM2FkY2I2OGYwNjYzNGU2MjkifQ%3D%3D; expires=Thu, 30-Apr-2020 13:35:06 GMT; Max-Age=7200; path=/; domain=localhost
Access-Control-Allow-Origin: http://localhost:8100

However, when I look at browser console I do not see anything set in storage > cookies. Furthermore there are no cookies attached to the subsequent call to `login/' and I receive a CSRF token mismatch error.

I have read through numerous posts detailing similar problems and implemented their recommendations and configurations including the following:

Laravel API

  • In .env I have set SESSION_DRIVER=cookie and SESSION_DOMAIN=localhost:8100
  • In config/sanctum I have added localhost:8100 to the stateful domains
  • In config/cors I have set supports_credentials = true and allowed all paths, headers and origins (using '*' value)

Angular SPA

  • I have implemented a global interceptor that sets withCredentials = true to all requests
  • I have ensured my api calls use //abc.api.hydrogen.com/ rather than http://abc.api.hydrogen.com/
  • I have also tried an interceptor to set the X-XSRF-TOKEN header as recommended here however the extracted token is null as they have not been set in the browser
1
I am also facing the same issue. I think the issue is that the XSRF-TOKEN cookie is not being set in the browser even though the cookie is there in the response. Hence the login request is failing because the request is not sending the XSRF-TOKEN. Can you check the cookies in the application once your sanctum/csrf-cookie request is completed?Alex Jose

1 Answers

2
votes

This problem occurred because the browser/angular will only attach cookies to requests that have the same domain as where the request is coming from.

To fix this in the dev environment where the angular app is being served on localhost and the Laravel app is on a domain like abc.api.hydrogen.local I proxied requests from the angular app:

First ensure your requests are relative routes, for example I changed my calls to /api/sanctum/crsf which then gets proxied to http://abc.api.hydrogen.local/sanctum/crsf

Then create a proxy configuration proxy.conf.json in the root of the project:

{
    "/api/*": {
      "target": "http://abc.api.hydrogen.local",
      "secure": false,
      "changeOrigin": true,
      "logLevel": "debug",
      "pathRewrite": {
        "^/api": ""
      }
    }
}

Then edit angular.json to use the proxy when it is serving:

"architect": {
    ...
    "serve": {
        ...
        "options": {
            ....
            "proxyConfig": "proxy.conf.json"
        }
    }
}

Finally in your .env file add the following to ensure that sanctum identifies requests as being from first party SPA's and the browser is able to read and attach cookies to the request.

SANCTUM_STATEFUL_DOMAINS=localhost,.hydrogen.local
SESSION_DRIVER=cookie
SESSION_DOMAIN=localhost

Now everything should work.