> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sinemacula.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quick Start: JWT Guard in 10 Minutes

> Set up your first JWT bearer-token guard, implement the Identity model, issue an access token, and protect a route — in under 10 minutes.

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.

<Note>
  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](/concepts/adoption-modes) for the 3D setup.
</Note>

<Steps>
  <Step title="Install the package">
    Add the package via Composer:

    ```bash theme={null}
    composer require sinemacula/laravel-authentication
    ```

    Publish the config file and the device migration, then run the migration:

    ```bash theme={null}
    php artisan vendor:publish --tag=authentication-config
    php artisan vendor:publish --tag=authentication-migrations
    php artisan migrate
    ```

    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.
  </Step>

  <Step title="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:

    ```dotenv theme={null}
    AUTHENTICATION_JWT_SECRET="a-strong-random-value-of-at-least-32-bytes"
    ```

    Generate a suitable value with `openssl rand -base64 48` or any equivalent tool. Keep this value out of version control.
  </Step>

  <Step title="Register the JWT guard">
    Open `config/auth.php` and register the `jwt` driver for your API guard, pointing it at your users provider:

    ```php theme={null}
    'guards' => [
        'api' => [
            'driver'   => 'jwt',
            'provider' => 'users',
        ],
    ],

    'providers' => [
        'users' => [
            'driver' => 'model',
            'model'  => App\Models\User::class,
        ],
    ],
    ```

    The `jwt` driver is registered automatically by the package's service provider. No additional bootstrapping is required.
  </Step>

  <Step title="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:

    ```php theme={null}
    <?php

    namespace App\Models;

    use Illuminate\Foundation\Auth\User as Authenticatable;
    use SineMacula\Laravel\Authentication\Contracts\Identity;
    use SineMacula\Laravel\Authentication\Contracts\Principal;
    use SineMacula\Laravel\Authentication\Traits\ActsAsPrincipal;
    use SineMacula\Laravel\Authentication\Traits\Authenticatable as StatelessAuthenticatable;

    class User extends Authenticatable implements Identity, Principal
    {
        use StatelessAuthenticatable, ActsAsPrincipal;
    }
    ```

    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`.
  </Step>

  <Step title="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:

    ```php theme={null}
    <?php

    namespace App\Http\Controllers;

    use App\Models\User;
    use Illuminate\Http\JsonResponse;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Hash;
    use SineMacula\Laravel\Authentication\Facades\Auth;

    class LoginController extends Controller
    {
        public function __invoke(Request $request): JsonResponse
        {
            $request->validate([
                'email'    => ['required', 'email'],
                'password' => ['required', 'string'],
            ]);

            $user = User::where('email', $request->input('email'))->first();

            if (!$user || !Hash::check($request->input('password'), $user->password)) {
                return response()->json(['message' => 'Invalid credentials.'], 401);
            }

            // In 2D mode: identity === principal. Pass null for device (access-only).
            $accessToken = Auth::jwt('api')->issueAccessToken($user, $user, null);

            return response()->json(['access_token' => $accessToken]);
        }
    }
    ```

    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.

    <Tip>
      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](/guides/refresh-rotation) for the full flow.
    </Tip>
  </Step>

  <Step title="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:

    ```php theme={null}
    // routes/api.php

    use Illuminate\Support\Facades\Route;
    use App\Http\Controllers\ProfileController;
    use App\Http\Controllers\LoginController;

    Route::post('/login', LoginController::class);

    Route::middleware('auth:api')->group(function () {
        Route::get('/me', ProfileController::class);
    });
    ```

    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:

    ```php theme={null}
    <?php

    namespace App\Http\Controllers;

    use Illuminate\Http\JsonResponse;
    use SineMacula\Laravel\Authentication\Facades\Auth;

    class ProfileController extends Controller
    {
        public function __invoke(): JsonResponse
        {
            $identity  = Auth::identity();   // App\Models\User — who authenticated
            $principal = Auth::principal();  // App\Models\User — who is acting (same in 2D)

            return response()->json([
                'id'    => $identity->getKey(),
                'email' => $identity->email,
                'role'  => $principal->role ?? null,
            ]);
        }
    }
    ```

    <Warning>
      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.
    </Warning>
  </Step>
</Steps>

## Next steps

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

<CardGroup cols={3}>
  <Card title="2D setup in depth" icon="user" href="/guides/2d-setup">
    Add active-state enforcement, device tracking, and a full login/refresh/logout flow to your 2D app.
  </Card>

  <Card title="Refresh rotation" icon="rotate" href="/guides/refresh-rotation">
    Issue refresh tokens, implement atomic rotation, and handle replay detection.
  </Card>

  <Card title="Identity, Principal, Device" icon="book-open" href="/concepts/identity-principal-device">
    Understand the three-context model and when each accessor returns what.
  </Card>
</CardGroup>
