> ## 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.

# Set Up HTTP Basic Authentication

> Register the basic guard driver for credential-based authentication with constant-time validation and configurable identifier field support.

The `basic` guard driver provides stateless HTTP Basic authentication backed by the same identity and principal pipeline as the JWT guard. It reads credentials from the standard `Authorization: Basic` header, validates them through a timing-safe path to prevent user enumeration, resolves the acting principal, and exposes the full contextual surface (`Auth::identity()`, `Auth::principal()`, `Auth::tenant()`) on every authenticated request.

## Registering the basic guard

Add a guard entry to `config/auth.php` with `driver: basic` and point it at a provider:

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

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

Protect routes by applying the guard as middleware:

```php theme={null}
Route::middleware('auth:cli')->group(function () {
    Route::get('/status', StatusController::class);
});
```

## How it works

On each request, the guard reads `PHP_AUTH_USER` and `PHP_AUTH_PW` from the PHP superglobals (via `Request::getUser()` / `Request::getPassword()`). If either is absent or empty, the guard returns `null` from `Auth::user()` without firing any events.

When credentials are present, the full pipeline runs inside a `Timebox`:

1. `Attempting` event fires.
2. The identity provider looks up the record by the configured `identifier_field`.
3. Laravel's hasher compares the supplied password against the stored hash.
4. If `CanBeActive` is implemented, `isActive()` is checked on the identity.
5. The principal resolver runs and `isActive()` is checked on the resolved principal.
6. On success, the identity and principal are bound to the guard and `Auth::user()` returns the identity.
7. On any failure, `Failed` fires and the guard returns `null`.

The entire pipeline runs within a constant-time `Timebox` window (default 400 ms) so the response time does not reveal whether the username exists.

<Warning>
  When running PHP behind **PHP-FPM and nginx**, the `Authorization` header is **not** automatically forwarded into `PHP_AUTH_USER` / `PHP_AUTH_PW`. Without explicit forwarding, the guard sees no credentials on every request and always returns `null`. Add the following directive to your nginx `fastcgi` block:

  ```nginx theme={null}
  location ~ \.php$ {
      fastcgi_pass_header Authorization;
      # ...rest of the fastcgi block
  }
  ```

  Apache with `mod_php` populates these superglobals automatically — the gotcha is specific to FastCGI transports. If your basic guard appears to never authenticate, this is the most likely cause.
</Warning>

## The `identifier_field` config

By default, the basic guard looks up identities by the `email` column. You can change this app-wide in `authentication.php`:

```php theme={null}
'credentials' => [
    'identifier_field' => 'email',
],
```

Any guard can override this with an `identifier_field` key in its `config/auth.php` entry. The per-guard value takes precedence over the package default.

## Multiple basic guards with different identifier fields

You can register multiple basic guards backed by different providers and keyed by different columns. A common pattern is an `email`-keyed guard for human users alongside a `key_id`-keyed guard for per-tenant service credentials:

```php theme={null}
'guards' => [
    'cli' => [
        'driver'   => 'basic',
        'provider' => 'users',
        // identifier_field omitted — falls back to `authentication.credentials.identifier_field` (default `email`)
    ],
    'tenant_api' => [
        'driver'           => 'basic',
        'provider'         => 'tenant_api_keys',
        'identifier_field' => 'key_id',
    ],
],

'providers' => [
    'tenant_api_keys' => [
        'driver' => 'model',
        'model'  => App\Models\TenantApiKey::class,
    ],
],
```

`TenantApiKey` implements `Identity` (and `Principal` in 2D mode). Its `key_id` column is what clients supply as the HTTP Basic username, and its `password` column holds the bcrypt hash of the API secret. The guard hashes and verifies the supplied secret using Laravel's configured hasher, exactly as it does for user passwords.

## Timing constant

The `basic` guard wraps the entire credential validation pipeline in Laravel's `Timebox` to prevent timing side-channels. The minimum elapsed time is controlled by:

```php theme={null}
'timebox' => [
    'credentials_microseconds' => 400000, // 400 ms default
],
```

This value must exceed the worst-case cost of your configured password hasher. If you increase bcrypt rounds or switch to Argon2, measure the maximum hash time under load and increase `credentials_microseconds` accordingly. Setting it too low defeats the timing-safety guarantee and re-introduces the user-enumeration side-channel the timebox is designed to close.
