# 13 - Backend Authentication Implementation

## Overview

Tenant authentication now uses a hybrid Sanctum setup:

- **Tenant Admin PWA** obtains Laravel Sanctum personal access tokens (PATs) via first-party endpoints under `/api/v1/tenant-auth/*`. Tokens carry ability strings (e.g. `tenant-admin`, `tenant:{id}`) and are required for all `/api/v1/tenant/*` routes.
- **First-party web flows** (marketing checkout, Filament admin, Google OAuth sign-in) rely on the classic session guard. When a session-based login needs API access (e.g. inside the PWA shell after a Google callback) the frontend exchanges the session for a PAT using the same Sanctum endpoints.
- **Legacy compatibility** is preserved through `/api/v1/tenant/me`, which now proxies the Sanctum-backed data while keeping the historical payload shape consumed by older clients.

All previous OAuth2/PKCE code paths, tables, and environment variables have been removed. No external authorization server is required.

## Tenant Admin PAT Flow

### Login
- **Endpoint**: `POST /api/v1/tenant-auth/login`
- **Body** (`application/json`):
  ```json
  {
    "login": "tenant@example.com",
    "password": "secret"
  }
  ```
  `login` accepts either an email address or username. Passwords are validated against the user record.
- **Response** (`200`):
  ```json
  {
    "token": "plain-text-pat",
    "token_type": "Bearer",
    "abilities": ["tenant-admin", "tenant:42"],
    "user": {
      "id": 17,
      "email": "tenant@example.com",
      "name": "Tenant Admin",
      "role": "tenant_admin",
      "tenant_id": 42
    }
  }
  ```
- **Failure codes**:
  - `422` with `login` field errors for invalid credentials, unverified email addresses, or roles without tenant access.
  - `429` throttle when the `tenant-auth` rate limit is exceeded.

Every successful login revokes any previous `tenant-admin` PAT for that user before issuing a new token. PATs are plain-text once in the response; the hash is stored in `personal_access_tokens`.

### Token Exchange (session → PAT)
- **Endpoint**: `POST /api/v1/tenant-auth/exchange`
- **Guards**: `web` session (cookies) with Sanctum stateful middleware.
- **Response**: identical payload to `/login`.
- **Usage**: The Tenant Admin PWA calls this after a browser session login (e.g. Google Socialite callback or marketing checkout user who opens the PWA shell) to synchronise state without a password prompt.

### Token Introspection & Logout
- **`GET /api/v1/tenant-auth/me`** (auth:sanctum) returns the current user, tenant snapshot, and active abilities for the PAT.
- **`POST /api/v1/tenant-auth/logout`** invalidates the current PAT and clears it from storage.
- **Legacy Proxy**: `/api/v1/tenant/me` now delegates to the new controller to return the historical payload seen by existing tooling while relying on Sanctum for authentication.

### Calling Tenant APIs
All tenant APIs continue to require the abilities enforced by middleware:
- `auth:sanctum` authenticates the PAT.
- `tenant.admin` gate checks that the user has `tenant-admin` or `super-admin` ability.
- `tenant.isolation` ensures the `tenant:{id}` ability matches the route tenant, guarding cross-tenant access.

Requests must send the PAT in the `Authorization: Bearer {token}` header. Tokens have no server-side expiration (`sanctum.expiration = null`); clients should refresh proactively (e.g. re-login) when a token is revoked or rejected.

## Session-Based Flows

### Marketing Checkout Login
- **Endpoint**: `POST /checkout/login`
- **Body**: `{ identifier, password, locale? }`
- **Remember behaviour**: the checkbox is hidden on the new Tenant Admin login screen but applied automatically – sessions persist via `Auth::login($user, true)`.
- Successful logins store a `redirect_intent` in the session when the flow originates from `/event-admin/*`, ensuring post-login navigation goes to `/event-admin/dashboard`.

### Tenant Admin PWA Login Screen
- The React shell renders `/event-admin/login` inside the PWA layout. It uses the same credentials form as `/checkout/login` but hits `/api/v1/tenant-auth/login` with fetch requests.
- After a successful PAT response, the token is persisted to both `localStorage` and `sessionStorage`; abilities are cached client-side to power feature flags.

### Google Sign-In
- Socialite handles the Google redirect/callback under `/event-admin/auth/google`.
- On success the user is logged into the web session, their email is marked verified (if needed), and the browser redirects back into the PWA shell.
- The shell immediately calls `/api/v1/tenant-auth/exchange` to obtain a PAT, keeping the flow consistent with password logins.
- Failures redirect back to the login page with query-string error codes that the PWA surfaces via i18n strings.

## Middleware & Guards

| Middleware | Purpose |
| --- | --- |
| `auth:sanctum` | Validates PATs issued by Sanctum. |
| `tenant.admin` | Ensures the authenticated user is a tenant admin or super admin. |
| `tenant.isolation` | Loads the tenant model by token ability and adds it to the request for downstream controllers. |
| `throttle:tenant-auth` | Rate limits login, exchange, and logout endpoints. |
| `EncryptCookies`, `AddQueuedCookiesToResponse`, `StartSession` | Applied to exchange routes so session cookies are available. |

## Security Considerations

- PATs are hashed at rest (`personal_access_tokens`), revocation is handled via database deletes.
- Tokens are limited to one active entry per user (`tenant-admin` name). Issuing a new token automatically stairs old devices out.
- All auth endpoints return generic validation errors to avoid username enumeration.
- Session regeneration occurs on every successful login (password or Google) to prevent fixation.
- Frontend storage keeps a second copy of the PAT in `sessionStorage` to reduce exposure when a user clears only persistent storage.
- Rate limits: configure `tenant-auth` in `RouteServiceProvider` (default `10 requests / minute`).
- CSP / XSRF: stateful Sanctum middleware is configured with `SANCTUM_STATEFUL_DOMAINS` so SPA requests inherit `XSRF-TOKEN` cookies automatically.

## Database & Infrastructure

- OAuth tables (`oauth_clients`, `oauth_codes`, `refresh_tokens`) have been removed. Sanctum uses the stock `personal_access_tokens` migration.
- No background jobs are required for PAT issuance or rotation.
- Audit requirements should log `personal_access_tokens` changes via database auditing (e.g. telescope/horizon logs) if needed.

## Configuration & Environment

Set the following environment variables to support the hybrid flow:

- `SANCTUM_STATEFUL_DOMAINS` – comma-separated list of domains running the Tenant Admin PWA (TWA, Capacitor, staging). Ensures cookies are considered first-party for the exchange endpoint.
- `SANCTUM_TOKEN_PREFIX` – optional prefix to enable secret-scanning detection.
- Remove the deprecated OAuth variables:
  - `VITE_OAUTH_CLIENT_ID`
  - `OAUTH_JWT_KID`
  - `OAUTH_KEY_STORE`
  - `OAUTH_REFRESH_*`

Google OAuth credentials (`GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`) remain for Socialite but only power the browser session login; token exchange happens through Sanctum.

## Testing

- Feature tests cover `/api/v1/tenant-auth/login`, `/exchange`, and `/logout` (`tests/Feature/Auth/TenantProfileApiTest.php`, `tests/Feature/TenantCreditsTest.php`).
- Frontend Playwright fixtures (`tests/e2e/utils/test-fixtures.ts`) provide helpers to obtain PATs when seeding test users.
- When adding new tenant API endpoints ensure coverage under Sanctum by using `->actingAs($user, 'sanctum')` in PHPUnit tests and by asserting abilities with `Sanctum::actingAs()` helpers where required.

This Sanctum-based approach keeps login logic inside the Laravel application, avoids custom OAuth infrastructure, and works uniformly across web, PWA, and the planned React Native wrapper.
