Custom Authentication Services
This chapter will guide you through the process of creating your own custom authentication service. This allows you to integrate any authentication method you need.
Creating a Custom Auth Service
First, you need to create a new class that will contain your authentication logic. It's a good practice to place this
class in the app/Services/Auth directory. For example, app/Services/Auth/MyCustomAuthService.php.
This class must implement at least the App\Services\Auth\Contract\AuthServiceInterface.
The Authentication Service Interfaces
There are three different interfaces that your authentication service can implement. Each interface adds a specific functionality to your service.
AuthServiceInterface
This is the basic interface that every authentication service must implement. It has one method: authenticate.
// app/Services/Auth/Contract/AuthServiceInterface.php
public function authenticate(Request $request): AuthenticatedUserInfo|Response;
This method is responsible for authenticating the user. It is called when a user tries to log in.
If the authentication is successful, it must return an AuthenticatedUserInfo object containing the user's details.
If the authentication fails (e.g., wrong credentials), the method should throw an AuthFailedException.
For authentication methods that require redirecting the user to an external login page (like OIDC or Shibboleth), this
method should return a Response object that performs the redirect.
If a technical error occurs (e.g., the authentication provider is unreachable), the method should throw an exception.
Here is a minimal example of an AuthServiceInterface implementation:
// app/Services/Auth/MyCustomAuthService.php
use App\Services\Auth\Contract\AuthServiceInterface;
use App\Services\Auth\Value\AuthenticatedUserInfo;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class MyCustomAuthService implements AuthServiceInterface
{
    public function authenticate(Request $request): AuthenticatedUserInfo|Response
    {
        // Your authentication logic here
        if (/* user is authenticated */) {
            return new AuthenticatedUserInfo(
                'unique-user-id',
                'username',
                'User Display Name',
                'employee'
            );
        }
        return redirect()->route('login');
    }
}
AuthServiceWithCredentialsInterface
This interface should be implemented if your authentication service uses a username and password. It adds two methods to
your service: useCredentials and forgetCredentials.
// app/Services/Auth/Contract/AuthServiceWithCredentialsInterface.php
public function useCredentials(string $username, string $password): void;
public function forgetCredentials(): void;
useCredentials: This method receives the username and password entered by the user on the login form. You should store them to use in theauthenticatemethod.forgetCredentials: This method is called after the authentication attempt to clear the stored credentials.
By implementing this interface, your service can be used with the default login form.
AuthServiceWithLogoutRedirectInterface
Implement this interface if you need to redirect the user to a specific URL after they log out. This is common for services like OIDC or Shibboleth where the logout needs to happen on the identity provider's side.
It has one method: getLogoutResponse.
// app/Services/Auth/Contract/AuthServiceWithLogoutRedirectInterface.php
public function getLogoutResponse(Request $request): ?RedirectResponse;
This method should return a RedirectResponse to the logout URL.
AuthServiceWithPostProcessingInterface
This interface can be implemented to perform actions after a user has been successfully authenticated. This is useful for tasks like logging the login event, updating user data, or redirecting the user to a specific page based on certain conditions.
It has two methods: afterLoginWithUser and afterLoginWithoutUser.
// app/Services/Auth/Contract/AuthServiceWithPostProcessingInterface.php
public function afterLoginWithUser(User $user, Request $request): Response|null;
public function afterLoginWithoutUser(AuthenticatedUserInfo $userInfo, Request $request): Response|null;
- 
afterLoginWithUser: This method is called after an existing user has been authenticated and the correspondingUsermodel has been retrieved from the database. It receives theUserobject and the currentRequest. It can return aResponseto redirect the user ornullto continue the normal login flow. - 
afterLoginWithoutUser: This method is called when a user authenticates successfully, but does not yet exist in the local database. This is the case when a user logs in for the first time. It receives anAuthenticatedUserInfoobject with the information from the authentication provider. It can return aResponseto redirect the user ornullto continue to the registration page. 
Using the Auth Utils
The app/Services/Auth/Util directory contains some helpful utilities to make creating your auth service easier.
- 
AuthServiceWithCredentialsTrait: You can use this trait to quickly implement theAuthServiceWithCredentialsInterface. It provides theuseCredentialsandforgetCredentialsmethods and stores the credentials in private properties.// app/Services/Auth/MyCustomAuthService.php
use App\Services\Auth\Contract\AuthServiceInterface;
use App\Services\Auth\Contract\AuthServiceWithCredentialsInterface;
use App\Services\Auth\Util\AuthServiceWithCredentialsTrait;
class MyCustomAuthService implements AuthServiceInterface, AuthServiceWithCredentialsInterface
{
use AuthServiceWithCredentialsTrait;
public function authenticate(Request $request): AuthenticatedUserInfo|Response
{
// You can now access $this->username and $this->password
// ...
}
} - 
AuthRedirectBuilder: This helper class can be used to build redirect responses, for example in yourgetLogoutResponsemethod. It allows you to easily add static query parameters as well as a list of build route urls as query parameters. This is useful to redirect the user back to a specific page after login/logout.$redirectResponse = AuthRedirectBuilder::build(
baseUrl: 'https://example.com/callback', // If this is empty (e.g. because not configured) null will be returned
routeQueryParams: [ 'next' => 'dashboard.home' ], // The full URL for the route "dashboard.home" will be added as the "next" query parameter
queryParams: [ 'foo' => 'bar' ], // Static query parameters
);
// This will create a redirect response to:
// https://example.com/callback?next=https%3A%2F%2Fexample.com%2Fdashboard&foo=bar - 
DisplayNameBuilder: This utility helps you build a display name for the user from one or more attributes. As an example you can combine first name and last name to create a full name:use App\Services\Auth\Util\DisplayNameBuilder;
DisplayNameBuilder::build(
'firstname,lastname',
fn(string $attribute) => $userAttributes[$attribute] ?? null
); 
Complete Example
Here is a more complete example of a custom authentication service that uses credentials and provides a custom logout redirect.
// app/Services/Auth/MyCustomAuthService.php
use App\Models\User;
use App\Services\Auth\Contract\AuthServiceInterface;
use App\Services\Auth\Contract\AuthServiceWithCredentialsInterface;
use App\Services\Auth\Contract\AuthServiceWithLogoutRedirectInterface;
use App\Services\Auth\Contract\AuthServiceWithPostProcessingInterface;
use App\Services\Auth\Util\AuthServiceWithCredentialsTrait;
use App\Services\Auth\Value\AuthenticatedUserInfo;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Response;
class MyCustomAuthService implements
    AuthServiceInterface,
    AuthServiceWithCredentialsInterface,
    AuthServiceWithLogoutRedirectInterface,
    AuthServiceWithPostProcessingInterface
{
    use AuthServiceWithCredentialsTrait;
    public function __construct(private readonly LoggerInterface $logger)
    {
    }
    public function authenticate(Request $request): AuthenticatedUserInfo|Response
    {
        // Authenticate the user with $this->username and $this->password
        if (/* authentication successful */) {
            return new AuthenticatedUserInfo($this->username, 'Display Name', 'user@example.com', 'employee');
        }
        // If no credentials are provided, or they are wrong, redirect to login
        return redirect()->route('login');
    }
    public function getLogoutResponse(Request $request): ?RedirectResponse
    {
        // Redirect to a custom logout page
        return redirect('https://my-auth-provider.com/logout');
    }
    public function afterLoginWithUser(User $user, Request $request): ?Response
    {
        $this->logger->info('User ' . $user->username . ' logged in successfully.');
        // No redirect needed, so return null
        return null;
    }
    public function afterLoginWithoutUser(AuthenticatedUserInfo $userInfo, Request $request): ?Response
    {
        $this->logger->info('New user ' . $userInfo->username . ' authenticated for the first time.');
        // No redirect needed, so return null
        return null;
    }
}
Registering Your Service
To use your new authentication service, you need to tell the application to use it. This is done via the
AUTHENTICATION_METHOD environment variable in your .env file.
Set the value of this variable to the fully qualified class name of your service:
AUTHENTICATION_METHOD="App\Services\Auth\MyCustomAuthService"
The application will then automatically use your custom service for authentication.
IMPORTANT: Make sure your service class is autoloadable by Composer!