Skip to main content
This guide walks you through the shortest path to a working JWT bearer-token guard: install the package, configure a guard, implement a minimal Identity model, issue an access token from a login controller, and protect a route. By the end you’ll have a fully functional stateless auth layer wired into Laravel’s standard Auth facade and middleware.
This quickstart uses 2D mode, where the Identity and Principal are the same model — the user who logs in is the actor on whose behalf every request runs. This is the right starting point for most apps. If you’re building a multi-tenant product where a single human can act as different tenant-scoped roles, see Adoption Modes for the 3D setup.
1

Install the package

Add the package via Composer:
Publish the config file and the device migration, then run the migration:
The migration creates the devices table used for refresh-token rotation and device tracking. If you only need access tokens and no refresh flow (common for M2M APIs), you can skip authentication-migrations entirely and omit the HasDevices contract from your model.
2

Set the JWT secret

Add your signing secret to .env. The package fails closed when a JWT guard is resolved with an empty or invalid secret — there is no silent fallback:
Generate a suitable value with openssl rand -base64 48 or any equivalent tool. Keep this value out of version control.
3

Register the JWT guard

Open config/auth.php and register the jwt driver for your API guard, pointing it at your users provider:
The jwt driver is registered automatically by the package’s service provider. No additional bootstrapping is required.
4

Implement the Identity model

Your user model needs to implement the Identity and Principal contracts and pull in the corresponding traits. In 2D mode, the same class satisfies both contracts:
A few things to note:
  • StatelessAuthenticatable re-exports Laravel’s own Authenticatable trait, but overrides the remember-token accessors with no-ops — this package is stateless and never writes a remember token.
  • ActsAsPrincipal provides the getPrincipalIdentifier() implementation required by the Principal contract, defaulting to the model’s primary key.
  • Point auth.providers.users.model at this class if it isn’t already App\Models\User.
5

Issue an access token

In your login controller, verify the user’s credentials and call Auth::jwt('api')->issueAccessToken() to mint a signed JWT. In 2D mode the identity and principal are the same model instance, and you pass null for the device when you’re not tracking devices:
The returned string is a signed JWT. Your client should store it and include it as a Bearer token in the Authorization header on subsequent requests.
When you’re ready to add refresh-token rotation and device tracking, implement HasDevices on your model, resolve or create a Device record at login, and pass it as the third argument. See Refresh Rotation for the full flow.
6

Protect a route and read context

Use the standard auth:api middleware to protect any route. The JWT guard validates the bearer token, rehydrates the identity from your provider, and resolves the principal automatically:
Inside the protected controller, use Auth::identity() and Auth::principal() to read the contextual values set by the guard. In 2D mode both return the same User instance:
Import SineMacula\Laravel\Authentication\Facades\Auth rather than Illuminate\Support\Facades\Auth to get IDE autocompletion for identity(), principal(), device(), tenant(), and type(). Both facades resolve through the same auth container key, so the package’s AuthManager is active either way.

Next steps

You now have a working JWT bearer-token guard. From here you can explore:

2D setup in depth

Add active-state enforcement, device tracking, and a full login/refresh/logout flow to your 2D app.

Refresh rotation

Issue refresh tokens, implement atomic rotation, and handle replay detection.

Identity, Principal, Device

Understand the three-context model and when each accessor returns what.