laravel / sanctum

Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.
https://laravel.com/docs/sanctum
MIT License
2.76k stars 296 forks source link

Receiving unauthenticated after successful login and receiving cookies #80

Closed mattg1995 closed 4 years ago

mattg1995 commented 4 years ago

Description:

After successfully hitting the airlock/csrf-cookie endpoint and logging in I still receive unauthenticated when hitting my API in subsequent requests. I can see the cookies being sent in the request (XSRF-TOKEN and the session) but it still will not authenticate with the airlock middleware.

Screenshot 2020-03-04 at 10 24 16

SESSION_DOMAIN=.hub.test AIRLOCK_STATEFUL_DOMAINS=front.hub.test

Cors config:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Laravel CORS Options
    |--------------------------------------------------------------------------
    |
    | The allowed_methods and allowed_headers options are case-insensitive.
    |
    | You don't need to provide both allowed_origins and allowed_origins_patterns.
    | If one of the strings passed matches, it is considered a valid origin.
    |
    | If array('*') is provided to allowed_methods, allowed_origins or allowed_headers
    | all methods / origins / headers are allowed.
    |
    */

    /*
     * You can enable CORS for 1 or multiple paths.
     * Example: ['api/*']
     */
    'paths' => ['api/*', 'airlock/csrf-cookie', 'login', 'logout'],

    /*
    * Matches the request method. `[*]` allows all methods.
    */
    'allowed_methods' => ['*'],

    /*
     * Matches the request origin. `[*]` allows all origins.
     */
    'allowed_origins' => ['*'],

    /*
     * Matches the request origin with, similar to `Request::is()`
     */
    'allowed_origins_patterns' => [],

    /*
     * Sets the Access-Control-Allow-Headers response header. `[*]` allows all headers.
     */
    'allowed_headers' => ['*'],

    /*
     * Sets the Access-Control-Expose-Headers response header.
     */
    'exposed_headers' => false,

    /*
     * Sets the Access-Control-Max-Age response header.
     */
    'max_age' => false,

    /*
     * Sets the Access-Control-Allow-Credentials header.
     */
    'supports_credentials' => true,
];

Please can you give some guidance on this, I have tried all the relevant channels (slack, discord etc) and still not able to solve the issue

Thank you

migueldevpt commented 4 years ago

This is happening to me too in the following project. https://github.com/migueldamaso/test-airlock

driesvints commented 4 years ago

Please ask this on a support channel.

Thanks.

mattg1995 commented 4 years ago

I have tried all relevant channels multiple times

mattg1995 commented 4 years ago

This seems to be a common issue amongst the people I've talked to in various channels. Would it be possible to look into this please would be appreciated @driesvints

simonmsara commented 4 years ago

@driesvints we would appreciate it if you stopped closing the issues without pointing to the solution, this is probably a bug. I am getting the unauthenticated response even when the SPA is served directly from the Laravel app.

danpastori commented 4 years ago

Did you try setting the SESSION_DRIVER to cookie? That did it for me.

migueldevpt commented 4 years ago

Hello everyone i managed to get my airlock app working. The problem was that the default AIRLOCK_STATEFUL_DOMAINS value is localhost. This means that if you are using artisan serve you must use localhost:8000 instead of 127.0.0.1:8000. I hope this helps

migueldevpt commented 4 years ago

If anyone needs my code is is https://github.com/migueldamaso/test-airlock And my .env is:

`APP_NAME=Laravel APP_ENV=local APP_KEY= APP_DEBUG=true APP_URL=http://localhost

LOG_CHANNEL=stack

DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE= DB_USERNAME= DB_PASSWORD=

BROADCAST_DRIVER=log CACHE_DRIVER=file QUEUE_CONNECTION=sync SESSION_DRIVER=file SESSION_LIFETIME=120

REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379

MAIL_MAILER=smtp MAIL_HOST=smtp.mailtrap.io MAIL_PORT=2525 MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_ENCRYPTION=null MAIL_FROM_ADDRESS=null MAIL_FROM_NAME="${APP_NAME}"

AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_DEFAULT_REGION=us-east-1 AWS_BUCKET=

PUSHER_APP_ID= PUSHER_APP_KEY= PUSHER_APP_SECRET= PUSHER_APP_CLUSTER=mt1

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" `

Don't forget the db credentials

driesvints commented 4 years ago

Hey everyone,

Over the past two months since Airlock was released we have gotten tons of issues involving cookies, CSRF, and other things. Every single one of them was the result of a misconfiguration somewhere or not reading the docs well enough.

We have dozens of open source repos to attend. There's still over 300 other issues that need my attention and I can't possible offer the same attention to every single one of them. This isn't a support channel and we have numerous other channels where there's a large community ready to help you out. Especially the Discord channel and Laracasts forums are very active.

Please try to use a support channel. If you find solutions to your problems we'd really appreciate a pr to the docs if something could be explained better.

@phiter calling people lazy isn't helping out anyone. We work hard to offer all of this for free.

driesvints commented 4 years ago

I also want to add that we appreciate it that you're using Airlock and want to help make it better. I'm genuinely sorry that I can't help out more. If I find some free time later on I'll maybe try to look into this.

taylorotwell commented 4 years ago

If there is a bug, find it and send a PR. Welcome to open source. Airlock is a simple package and doesn’t contain much code. Airlock works for me and others and as Dries noted all of these issues have been configuration problems so far. But, we welcome and look forward PRs to fix any bugs.

simonmsara commented 4 years ago

Hi guys, I would like to start by saying your efforts and contributions to the industry are greatly appreciated and we do not take them for granted, even though we throw our toys out of the pram here and there; it's not you it's us 😂.

I think I might have found the issue that's causing the authentication failure – Airlock's guard is trying to get the user from the 'web' guard which is returning null but switching to the 'api' guard is returning the authenticated user. If it's not a bug then this might be a clue as to why it's failing?

Thanks again for the help ✌️

simonmsara commented 4 years ago

I think I might have found the issue that's causing the authentication failure – Airlock's guard is trying to get the user from the 'web' guard which is returning null but switching to the 'api' guard is returning the authenticated user. If it's not a bug then this might be a clue as to why it's failing?

The 'web' guard is used to get the authenticated user instance but this can be changed in the auth config by changing the default guard to anything else. I have made a PR to use the configured default guard but still pass in the 'web' as a fallback. If this isn't the way to go we will need to update the docs to say your default guard should be set to 'web'.

evansmwendwa commented 4 years ago

The issue tends to be in one of two areas. AIRLOCK_STATEFUL_DOMAINS configuration or the auth guard for your routes which needs to be updated yo use airlock

phiter commented 4 years ago

In my case I had the default guard as api, but airlock only works with web so I needed to run auth('web')->login($user); and it worked

nolros commented 4 years ago

The key issue here are the cookies. You need to manage them manually if you have any hope of making this work in production. For example, if you login and then attempt to login again via JS, the guard will identify you as logged in and redirect you to home, which will result in html in your data field. Even if youauth('web')->logout($user), you will still run into the issue that it might not logout as Sanctum looks to the cookies to determine logged in status. Sometimes you can authenticate but because of the cookies your status will still remain unauthenticated. Therefore, if you logout you need to delete the cookies manually to be ensure you have actually logged out. If you login, you need to delete the cookies. You can decorate Authenticate middleware to do a number of checks and also config middleware in your Auth controllers. Other option create your own middleware, and/or decorate the Auth controllers of Auth::routes and/or make your own Auth controller and remove Auth::routes. If you use Vuex and VueRouter then you need to implement the same Laravel guard logic.

bciriak commented 4 years ago

Hey guys, for me the problem was that I was setting the "SANCTUM_STATEFUL_DOMAINS" to my api domain which sits on port 8000 (localhost:8000). When I changed it to my Vue SPA domain port which is 8080 (localhost:8080) it worked. So maybe just check that.

ianrussel commented 4 years ago

@driesvints we would appreciate it if you stopped closing the issues without pointing to the solution, this is probably a bug. I am getting the unauthenticated response even when the SPA is served directly from the Laravel app.

Did you solve this? I also have this issue. My react js lives in same laravel project, inside resources/js

morris14 commented 4 years ago

Setting 'SANCTUM_STATEFUL_DOMAINS' works for me. Thanks for all the hard work @taylorotwell @driesvints 👍

vermadilipjpr commented 4 years ago

Try like this: Auth::login($user, true); It might help.

tsangaris commented 4 years ago

I have the same issue with API to be http://api.example.test (Homestead) and my VUE Cli SPA to be at http://example.test:3000.

Don't know how to overcome this issue with the 401 Unauthenticated.

Any ideas?

=======================

Turns out that while creating my user in Tinker, for some reason Hash::make('password'); went wrong. So i couldn't authenticate due to wrong password.

ipearx commented 4 years ago

Anyone new, be aware to use SANCTUM_STATEFUL_DOMAINS instead of AIRLOCK_STATEFUL_DOMAINS in your .env file.

That's what caught me out. I'm guessing the name of the project changed through development? So some comments are old and use the wrong name. This will be needed if you're using a custom domain e.g. I use myprojectname.test locally. Would be good to add this to the documentation.

stanliwise commented 4 years ago

For anyone having the Unauthentication error, please ensure you follow this steps.

After this step you will be successfully authenticated by auth:sanctum middleware in API route.

Other things to be aware of:

  1. Ensure your SESSION_DOMAIN is set to localhost or your host without port
  2. SANCTUM_STATEFUL_DOMAIN is set to your sub domain/SPA IP with the port e.g localhost:8000
    1. Also set SESSION_DRIVER=cookie
insidert commented 4 years ago

This is because of misconfiguring the sanctum and session domains.

SANCTUM_STATEFUL_DOMAINS=localhost:8080,127.0.0.1:8080,localhost:3000,127.0.0.1:3000
SESSION_DOMAIN=localhost
'paths' => ['api/*', 'login', 'register', 'otp/*', 'sanctum/csrf-cookie'],

'supports_credentials' => true,
ipearx commented 4 years ago

@insidert

Make sure the laravel app is serving from localhost (127.0.0.1) by doing the good old php artisan serve. Do not use virtual hosts...

I'm using Sanctum with Apache Virtual Hosts even with wildcard subdomains, and it works fine once I set the stateful domains correctly. My front end is served by the same app as my backend. Keep in mind some apps have to share web servers when deployed.

I'm using this config in my .env file:

SANCTUM_STATEFUL_DOMAINS=.mydomain.test,mydomain.test
Aslam97 commented 4 years ago

Setting SANCTUM_STATEFUL_DOMAINS without protocol. Setting SESSION_DRIVER to cookie Include login in paths and enable supports_credentials work for me

csimpi commented 3 years ago

@Aslam97 Are you sure you need to set SESSION_DOMAIN to cookie? I think you mix it up with SESSION_DRIVER which value should be cookie indeed

Aslam97 commented 3 years ago

@csimpi ah my mistake. edited

hectordommo commented 3 years ago

Some other tip is that you have to setup EnsureFrontendRequestsAreStateful in the api middlewareGroups at app/Http/Kernel.php as so:

'api' => [
            EnsureFrontendRequestsAreStateful::class,
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
altercode commented 3 years ago

For those who are using NEXT JS as an SPA DO NOT call axios from inside getServerSideProps or getStaticSiteProps! Instead use useEffect hook to fetch data from external API.

esmaily commented 3 years ago

I'm config all settings for sanctum but not working. SESSION_DRIVER=cookie SESSION_DOMAIN=localhost SANCTUM_STATEFUL_DOMAINS=localhost,127.0.0.1:8000,localhost:3000 'supports_credentials' => true, 'paths' => [ 'api/*', 'login', 'register', 'logout', 'sanctum/csrf-cookie' ], axios.defaults.withCredentials = true

budiodank commented 3 years ago

If you are using PHP FastCGI and Apache to serve your Laravel application, HTTP Basic authentication may not work correctly. To correct these problems, the following lines may be added to your application's .htaccess file:

RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

Reference : https://laravel.com/docs/8.x/authentication

elidrissidev commented 2 years ago

FWIW, I was scratching my head for a full day only to realize the issue was related to browser cache, switching to Firefox worked. :shrug:

SinMu-L commented 2 years ago

这是因为错误配置了 sanctum 和 session 域。

  • 确保 laravel 应用程序从 localhost (127.0.0.1) 提供服务,方法是做旧的php artisan serve.不要使用虚拟主机,因为您无法从同一虚拟主机提供前端应用程序。
  • 检查前端应用程序的端口号。通常,React 应用服务于http://localhost:3000.Vue 应用服务于http://localhost:8080.
  • _前端应用程序_和_laravel 应用程序_必须从同一个域提供服务 - 在我们的例子中是 localhost。
  • 在.env 文件中设置圣所状态域。这些是我们前端应用程序的地址,包括端口号。
SANCTUM_STATEFUL_DOMAINS=localhost:8080,127.0.0.1:8080,localhost:3000,127.0.0.1:3000
  • 在.env 文件中设置会话域。您需要在生产时将其更改为您的域名。
SESSION_DOMAIN=localhost
  • 在 cors.php 中设置路径和 support_credentails 您希望在前端应用程序中访问的 web.php的_路由_应_添加_到路径数组。****__
'paths' => ['api/*', 'login', 'register', 'otp/*', 'sanctum/csrf-cookie'],

'supports_credentials' => true,
  • 最后,您应该从前端应用程序向_localhost/api/other-route_发出请求,而不是使用 axios向127.0.0.1/api/other-route发出请求。

Thanks I modified the configuration as follows .env

SESSION_DRIVER=cookie
SANCTUM_STATEFUL_DOMAINS=127.0.0.1:8000
SESSION_DOMAIN=127.0.0.1

Then start laravel by command php artisan serve

lcsfort commented 1 year ago

Hello everyone, for me the solution was to add the \Illuminate\Session\Middleware\StartSession::class middleware in the api middlewareGroups at app/Http/Kernel.php

'api' => [ 
    \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    \Illuminate\Session\Middleware\StartSession::class
],
stanliwise commented 1 year ago

Hello everyone, for me the solution was to add the \Illuminate\Session\Middleware\StartSession::class middleware in the api middlewareGroups at app/Http/Kernel.php

'api' => [ 
    \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    \Illuminate\Session\Middleware\StartSession::class
],

Never use a session on api calls that would reap open your api to cross site script attack. It’s dangerous

lcsfort commented 1 year ago

@stanliwise Thanks 🙏

stanliwise commented 1 year ago

@stanliwise Thanks 🙏

Sanctum session auth is basically for SPA applications that uses the cookie based authentication. If you’re using api calls simple use the plain text token method and pass it as bearer.

lcsfort commented 1 year ago

@stanliwise I'm using sanctum cookie-based auth strategy for a react SPA

stanliwise commented 1 year ago

@stanliwise I'm using sanctum cookie-based auth strategy for a react SPA

Are you aware of

EnsureFrontendRequestsAreStateful middleware?

lcsfort commented 1 year ago

Yes, I'm aware of it. I'm using it as well.

chimobi-justice commented 11 months ago

I guess the best way go configure your laravel sanctum and SPA is to configure your laravel ENV file properly and also add the withCredentials: true, at your axios config it works for me