Passport — full OAuth2 server in Laravel
Concept
Custom guards allow implementing non-standard authentication mechanisms — API key authentication, JWT verification, or authenticating against an external system (LDAP, SSO provider).
Guard contract: Illuminate\Contracts\Auth\Guard. Two key methods: user() (return the authenticated user or null) and check() (return bool). For stateful guards: login(), logout(), attempt().
StatefulGuard: Extends Guard with attempt(), login(), loginUsingId(), once(), logout(). The session guard implements this.
RequestGuard: The simplest guard — a closure-based guard registered with Auth::viaRequest(). Takes the request and returns a user model or null. Perfect for stateless API key guards.
UserProvider: Handles finding users from the database. The default EloquentUserProvider finds by credentials. Custom providers implement Illuminate\Contracts\Auth\UserProvider: retrieveById(), retrieveByToken(), updateRememberToken(), retrieveByCredentials(), validateCredentials().
Registering custom guards: In AuthServiceProvider::boot(): Auth::extend('custom-driver', fn($app, $name, $config) => new CustomGuard(...)).
Registering custom providers: Auth::provider('custom-provider', fn($app, $config) => new CustomProvider(...)).
Code Example
<?php
// Simple closure-based API key guard — in AuthServiceProvider::boot()
use Illuminate\Support\Facades\Auth;
Auth::viaRequest('api-key', function(\Illuminate\Http\Request $request): ?User {
$apiKey = $request->header('X-API-Key') ?? $request->query('api_key');
if (!$apiKey) return null;
return User::where('api_key', hash('sha256', $apiKey))->first();
});
// config/auth.php — register the guard
'guards' => [
'api-key' => [
'driver' => 'api-key', // matches Auth::viaRequest name
'provider' => 'users',
],
],
// Use in routes
Route::middleware('auth:api-key')->get('/api/data', function() {
return response()->json(['user' => auth('api-key')->user()]);
});
// Full custom Guard class — for complex stateless guards
class JwtGuard implements \Illuminate\Contracts\Auth\Guard
{
use \Illuminate\Auth\GuardHelpers;
public function __construct(
private \Illuminate\Contracts\Auth\UserProvider $provider,
private \Illuminate\Http\Request $request,
) {}
public function user(): ?User
{
if ($this->user !== null) return $this->user;
$token = $this->request->bearerToken();
if (!$token) return null;
try {
$payload = \Firebase\JWT\JWT::decode($token, new \Firebase\JWT\Key(config('app.key'), 'HS256'));
return $this->user = $this->provider->retrieveById($payload->sub);
} catch (\Exception) {
return null;
}
}
public function validate(array $credentials = []): bool
{
return $this->provider->retrieveByCredentials($credentials) !== null;
}
}
// Register in AuthServiceProvider
Auth::extend('jwt', function($app, $name, $config) {
return new JwtGuard(
Auth::createUserProvider($config['provider']),
$app['request']
);
});