Files
fotospiel-app/docs/prp/13-backend-authentication.md

7.7 KiB
Raw Blame History

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):
    {
      "login": "tenant@example.com",
      "password": "secret"
    }
    
    login accepts either an email address or username. Passwords are validated against the user record.
  • Response (200):
    {
      "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.