# Authentication
You can use standard Laravel mechanisms (opens new window) to authenticate users of your GraphQL API.
# AttemptAuthentication middleware
As all GraphQL requests are served at a single HTTP endpoint, middleware added
through the lighthouse.php
config will run for all queries against your server.
In most cases, your schema will have some publicly accessible fields and others that require authentication. As multiple checks for authentication or permissions may be required in a single request, it is convenient to attempt authentication once per request.
'route' => [
'middleware' => [
\Nuwave\Lighthouse\Http\Middleware\AttemptAuthentication::class,
],
],
Note that the AttemptAuthentication
middleware does not protect your fields from unauthenticated
access, decorate them with @guard as needed.
If you want to guard all your fields against unauthenticated access, you can simply add Laravel's build-in auth middleware. Beware that this approach does not allow any GraphQL operations for guest users, so you will have to handle login outside GraphQL.
'middleware' => [
'auth:api',
],
# Configure the guard
You can configure default guards to use for authenticating GraphQL requests in lighthouse.php
.
'guards' => ['api'],
This setting is used whenever Lighthouse looks for an authenticated user, for example in directives
such as @guard, or when applying the AttemptAuthentication
middleware.
When multiple guards are configured, the first one that is authenticated will be used.
Stateless guards are recommended for most use cases, such as the default api
guard.
# Laravel Sanctum
If you are using Laravel Sanctum (opens new window) for your API, set the guard
to sanctum
and register Sanctum's EnsureFrontendRequestsAreStateful
as the first middleware for Lighthouse's route.
'route' => [
// ...
'middleware' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
// ... other middleware
],
],
'guards' => ['sanctum'],
Note that Sanctum requires you to send an CSRF token as header (opens new window) with all GraphQL requests, regardless of whether the user is authenticated or not.
When using mll-lab/laravel-graphiql (opens new window), follow the instructions to add a CSRF token (opens new window).
# Guard selected fields
Use the @guard directive to require authentication for a single field.
type Query {
profile: User! @guard
}
If you need to guard multiple fields, use @guard
on a type
or an extend type
definition. It will be applied to all fields within that type.
extend type Query @guard {
adminInfo: Secrets
nukeCodes: [NukeCode!]!
}
The @guard
directive will be prepended to other directives defined on the fields
and thus executes before them.
extend type Query {
user: User!
@guard
@canModel(ability: "adminOnly")
...
}
# Get the current user
Lighthouse provides a really simple way to fetch the information of the currently authenticated user.
Just add a field that returns your User
type and decorate it with the @auth directive.
type Query {
me: User @auth
}
Sending the following query will return the authenticated user's info
or null
if the request is not authenticated.
{
me {
name
email
}
}
# Stateful Authentication Example
You can create or destroy a session with mutations instead of separate API endpoints (/login
, /logout
).
This only works when Lighthouse's guard uses a session driver.
Laravel's token based authentication does not allow logging in or out on the server side.
The implementation in the docs is only an example and may have to be adapted to your specific use case.
Add the following middleware to config/lighthouse.php
:
'route' => [
// ...
'middleware' => [
// Either those for plain Laravel:
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// Or this one when using Laravel Sanctum:
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
// ... other middleware
],
],
The login
and logout
might be defined and implement like this:
type Mutation {
"Log in to a new session and get the user."
login(email: String!, password: String!): User!
"Log out from the current session, showing the user one last time."
logout: User @guard
}
use App\Models\User;
final class Login
{
/**
* @param null $_
* @param array<string, mixed> $args
*/
public function __invoke($_, array $args): User
{
// Plain Laravel: Auth::guard()
// Laravel Sanctum: Auth::guard(Arr::first(config('sanctum.guard')))
$guard = ?;
if( ! $guard->attempt($args)) {
throw new Error('Invalid credentials.');
}
$user = $guard->user();
assert($user instanceof User, 'Since we successfully logged in, this can no longer be `null`.');
return $user;
}
}
final class Logout
{
/**
* @param null $_
* @param array<string, mixed> $args
*/
public function __invoke($_, array $args): ?User
{
// Plain Laravel: Auth::guard()
// Laravel Sanctum: Auth::guard(Arr::first(config('sanctum.guard', 'web')))
$guard = ?;
$user = $guard->user();
$guard->logout();
return $user;
}
}