I am trying to get my custom authentication workflow up and running. For this I am using an additional database table called "clients", an additional provider 'clients' and an additional guard called 'vcs' for the authentication workflow. Clients get a signed URL to login. For this I am using the ´Auth´-facade's login-method right after creating a client in the database. The login is working perfectly fine and a session cookie is generated.
The problem is, that all subsequent requests to laravel's API routes result in 401 errors - although the session cookie is sent with the request.
I already posted a very detailed thread over on stackoverflow.com:https://stackoverflow.com/questions/74336763/laravel-9-user-not-authenticated-on-api-routes-using-custom-guard
I did not want to cross-post but lately I don't see any real progress on my laravel-related questions over there and it seems like stackoverflow is no more a good place to ask questions and to get qualified answers for laravel-specific problems.
I would be very glad to find some help over here.
config/auth.php:
<?php
return [
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'vcs' => [
'driver' => 'session',
'provider' => 'clients',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'clients' => [
'driver' => 'eloquent',
'model' => App\Models\Client::class,
],
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
'password_timeout' => 10800,
];
My client model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Client extends Authenticatable
{
use HasFactory, HasApiTokens;
protected $guard = "vcs";
/**
* The primary key associated with the table.
*
* @var string
*/
protected $primaryKey = 'uuid';
/**
* Indicates if the model's ID is auto-incrementing.
*
* @var bool
*/
public $incrementing = false;
protected $keyType = 'string';
/**
* Get the route key for the model.
*
* @return string
*/
public function getRouteKeyName()
{
return 'uuid';
}
}
The clients get a signed URL which points to the following controller action. The action checks for a valid query parameter in the URL (simplified for this thread). After that a new Client model gets created and the new Client gets logged in using the 'vcs' guard:
<?php
namespace App\Http\Controllers\VCS;
use Illuminate\Http\Request;
use App\Models\Client;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Auth;
class AuthController extends Controller
{
public function redirectWithCookie(Request $request)
{
// reduced for the sake of simplicity here
$credential = $request->someURLParameter;
if ($credential) {
$client = new Client;
$client->uuid = Str::uuid()->toString();
$client->ip = $request->ip();
$client->status = 'pending';
$client->save();
Auth::guard('vcs')->login($client, $remember = true);
// this logs the authenticated user correctly!
Log::info('Authenticated User: ' . Auth::guard('vcs')->user());
$cookieValue = json_encode(array('uuid' => $client->uuid));
$cookie = cookie('mycookie', $cookieValue);
$redirectUrl = config('my.redirect.url');
return redirect()->away($redirectUrl)->withCookie($cookie);
}
return response(['message' => 'Invalid URL', 'error' => 'url'], 422);
}
}
routes/web.php:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\VCS\AuthController;
Route::get('/', function () {
return ['Laravel' => app()->version()];
});
Route::get('vcs/auth', [AuthController::class, 'redirectWithCookie'])->name('vcs.auth');
require __DIR__.'/auth.php';
routes/api.php:
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\VCS\RoomController;
Route::middleware(['auth:sanctum'])->get('/user', function (Request $request) {
return $request->user();
})->name('profile');
Route::middleware(['auth:vcs'])->group(function () {
Route::get('rooms', [RoomController::class, 'rooms']);
});
After the redirect I get a laravel_session as a cookie which should authenticate my subsequent requests. The problem is that I can't call any API routes with the custom guard and I am not authenticated anymore although the browser is sending my session cookie with the request. For example calling the /api/rooms GET-endpoint defined in the api.php results in a redirect to the login page.
I also see that the user is not authenticated in the auth-middleware:
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* @param \Illuminate\Http\Request $request
* @return string|null
*/
protected function redirectTo($request)
{
Log::info('Authenticated User: ' . Auth::guard('vcs')->user());
}
}
The Log just returns an empty string so the user is not authenticated:
[2022-11-06 13:44:30] local.INFO: Authenticated User:
So my question is: How can I use a custom guard for my API routes after manually logging new users in?
I also tried the same workflow using Insomnia as a REST Client:
Login by URL:

whichs gives me a sessions cookie.
Access some API Route:

Which results in an Unauthorized-Status-Code..