I didn't test it, but I think you can create a custom guard that calls both guards under the hood.
This should work, or at least give you a path:
namespace App;
use Illuminate\Auth\GuardHelpers;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Factory;
use Illuminate\Contracts\Auth\Guard;
use KeycloakGuard\KeycloakGuard;
use Laravel\Passport\Guards\TokenGuard;
class AppGuard implements Guard
{
use GuardHelpers;
private TokenGuard $passport;
private KeycloakGuard $keycloak;
public function __construct(Factory $auth)
{
$this->passport = $auth->guard('passport');
$this->keycloak = $auth->guard('keycloak');
}
public function user()
{
if (! is_null($this->user)) {
return $this->user;
}
$user = $this->passport->user()
?? $this->keycloak->user();
return \tap($user, fn () => $this->setUser($user));
}
public function validate(array $credentials = [])
{
return $this->passport->validate($credentials)
|| $this->keycloak->validate($credentials);
}
public function setUser(Authenticatable $user)
{
$this->user = $user;
$this->passport->setUser($user);
$this->keycloak->setUser($user);
}
}
Then you register this custom guard on a service provider and configure on your ./config/auth.php file, so your API routes use this guard.
You can find instructions on how to do it here in the docs:
https://laravel.com/docs/9.x/authentication#adding-custom-guards