# Authentication and authorization

## Two token domains

Staff and suppliers use **different** Sanctum tokenables and storage keys in the browser.

```mermaid
flowchart LR
  subgraph Staff["Staff workspace"]
    U[User model]
    T1[personal_access_tokens tokenable_type User]
    LS[localStorage auth_token]
  end

  subgraph Supplier["Supplier portal"]
    V[VendorPortalAccount model]
    T2[personal_access_tokens tokenable_type VendorPortalAccount]
    LV[localStorage ngoerp_vendor_portal_token]
  end

  U --- T1
  LS -.->|Bearer| T1
  V --- T2
  LV -.->|Bearer| T2
```

## Staff login sequence

```mermaid
sequenceDiagram
  participant C as Client
  participant API as POST /api/login
  participant RL as RateLimiter
  participant DB as users

  C->>API: email + password
  API->>RL: throttle key
  alt too many attempts
    RL-->>C: 422 throttle
  else ok
    API->>DB: find user
    alt invalid credentials
      API-->>C: 422 auth.failed
    else valid
      API->>DB: createToken api
      API-->>C: token + user JSON
    end
  end
```

## Staff authenticated request pipeline

```mermaid
flowchart TD
  A[Request Bearer token] --> S[auth:sanctum]
  S --> T2F[two_factor.workspace]
  T2F --> OM{org.member + tenant.actor}
  OM --> RB[rbac.context + rbac.headers]
  RB --> MD{module middleware}
  MD --> CTL[Controller + Policy / RBAC privilege]
```

> Exact middleware names and order: see `routes/api.php` and `bootstrap/app.php` aliases.

## Workspace two-factor (high level)

```mermaid
stateDiagram-v2
  [*] --> Authenticated: valid Sanctum token
  Authenticated --> Blocked: 2FA required and not satisfied
  Authenticated --> Allowed: 2FA ok or not required
  Blocked --> Allowed: step-up or TOTP challenge completed
  Allowed --> [*]
```

## Vendor portal login

```mermaid
sequenceDiagram
  participant C as Client
  participant API as POST .../vendor-portal/login
  participant DB as vendor_portal_accounts

  C->>API: org UUID + email + password
  API->>DB: match org_id + email
  alt invalid
    API-->>C: 422
  else valid
    API->>DB: createToken vendor-portal
    API-->>C: token + portal payload
  end
```

## Vendor portal routes (isolation)

```mermaid
flowchart LR
  subgraph Public["Unauthenticated"]
    VH[GET vendor-hub]
    VR[POST vendor-registrations]
    VL[POST vendor-portal/login]
  end

  subgraph VP["auth:sanctum + vendor.portal"]
    ME[GET/PATCH me]
    PW[PATCH password]
    OP[GET opportunities]
    BD[POST opportunities uuid bids]
    LO[POST logout]
  end

  VL -->|token| VP
```

Staff `User` tokens **must not** hit `vendor.portal` routes (403). Vendor tokens **must not** pass `org.member` workspace routes (403 / wrong tokenable).

## RBAC (when enabled)

```mermaid
flowchart TB
  subgraph Catalog["Definitions"]
    FR[functional_roles]
    PR[privileges]
    DS[data_scopes]
  end

  subgraph Runtime["Per request"]
    CTX[rbac.context]
    ASG[assignments user to role + scope]
    GATE[Privilege checks in controllers]
  end

  FR --> ASG
  DS --> ASG
  PR --> GATE
  CTX --> GATE
```

Privilege constants live under `App\Support\RbacPrivilege` (referenced from controllers).
