I am currently trying to create a simple authentication feature using Laravel (v9.52.4) and Sanctum. From the frontend I am currently using Axios to get and post data. Both frontend and backend API are running on localhost (http://121.0.0.1:8000) but the API endpointscan be reached at http://121.0.0.1:8000/api/v1/{endpoint here}
When I try to log in, everything seems to be running as expected but no CSRF cookies are being send/set by the backend API. If I use the correct login credentials (email + password) the tokens get generated on the backend, get stored in the database and also sends a response that the login was successful - of course if the credentials are invalid no token gets generated and I recieve the proper response. (So the login logic seems to be working fine, but without the CSRF cookies I can't authorize myself on the admin subpages so it simply redirects me to the login page even after a successful login)
I have been searching for the solution, but with no luck so far. You can find all the files/pieces of code that might be relevant for this issue:
.env (The ROOT_URL variable is used to create HTML and Javascript URLs on frontend)
APP_URL=http://127.0.0.1:8000
...
SESSION_DOMAIN = "127.0.0.1:8000"
SANCTUM_STATEFUL_DOMAINS = "127.0.0.1:8000"
ROOT_URL="http://127.0.0.1:8000"
.AuthController - /login route uses this controller's functions
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Response;
class AuthController extends Controller
{
public function login(Request $request){
$credentials = [
'email' => $request->email,
'password' => $request->password
];
if(Auth::attempt($credentials)){
$authUser = Auth::user();
$success['token'] = $authUser->createToken('APIToken')->plainTextToken;
$success['name'] = $authUser->name;
return response()->json(['user' => $success], 200);
}
else {
return response()->json(['error' => "Unauthenticated"], 404);
}
}
public function logout(Request $request, $isAPI = true){
$request->session()->invalidate();
$request->session()->regenerateToken();
auth()->user()->tokens()->delete();
if($isAPI){
return response()->json(['msg' => "user logged out"], 200);
}
return view('admin.login');
}
}
cors.php
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
Kernel.php (I have imported and added the middleware)
...
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
...
Frontend Axios handlers
const API_ROOT = `${ROOT_URL}/api/v1`
axios.defaults.withCredentials = true
async function loginUser(credentials){ //these credentials are coming from the HTML form inputs
const CSRF = `${ROOT_URL}/sanctum/csrf-cookie`
const LOGIN_URL = `${API_ROOT}/login`
toggleLoader()
await axios.get(CSRF)
await axios.post(LOGIN_URL, credentials)
.then((res) => handleResponse(res.data))
.catch((err) => console.log(err))
.finally(() => toggleLoader())
}
function handleResponse(response){
if(response.user){
console.log(`Logged in as ${response.user.name}`)
window.location.replace(`${ROOT_URL}/admin`)
return
}
console.log('failed to log in')
}
I really hope that someone has already met with this problem and can give me a helping hand. Thank you all for any help or suggestions!
Have a great day!
Sidenote: The authentication process (creating tokens, setting the cookies and logging in) was working when I was using the XAMPP for local hosting. Then I moved the project out of the htdocs directory and started hosting using php artisan serve command. Everything else (database, routes, etc.) is still working besides setting the CSRF cookies.
I finally managed to figure out a solution - the problem was mainly related to misconfigured domains. I have also deployed the project on a live server and it is working fine there as well.
Here are my settings from .env file, that fixed my issue:
APP_URL=http://127.0.0.1:8000
SESSION_DOMAIN=127.0.0.1
SESSION_DRIVER=cookie
SANCTUM_STATEFUL_DOMAINS=127.0.0.1:8000
ROOT_URL=//127.0.0.1:8000
Note: ROOT_URL is being used when fetching the API! (So in my js file it looks like this: //127.0.0.1:8000/api/v1/login)
Seems like it's quite important where to/not to feautre the scheme and port (':8000', 'http', etc...) in the URL.
I really hope this solution will help some people out there. :)