**Plugin Domain Reset & Revoke Policy**

Summary
- Purpose: describe admin actions for managing plugin domain binding and access: `Revoke`, `Reset (cooldown)`, and `Reset (immediate)`.
- Audience: admins, integrators, and engineers operating the plugin authorization flow.

Actions and semantics
- Revoke (admin action)
  - What: mark `plugin_revoked_at = now()` and set `is_auth_token = false`.
  - Effect: immediately prevents issuance or acceptance of JWTs. Plugin requests to `/api/plugin/token` return 403 with `Plugin access revoked`.
  - Use when: a license must be immediately disabled (compromise, non-payment, contract termination).

- Reset (cooldown) (admin action)
  - What: clear `plugin_domain_hash`, clear `plugin_authorized_at`, set `is_auth_token = false`, set `plugin_domain_reset_requested_at = now()`, increment `plugin_domain_reset_count`.
  - Effect: domain binding is removed but a cooldown window prevents re-authorization for a configured period (default 30 days). Token issuance and authorization emails are rejected during cooldown with a 403 JSON containing `error: "Domain reset cooldown in effect"` and `cooldown_expires_at` timestamp.
  - Use when: you want to unbind a domain but prevent rapid re-binds (mitigate social-engineering or frequent churn), or when you require a waiting period for security/audit reasons.

- Reset (immediate) (admin action)
  - What: clear `plugin_domain_hash`, clear `plugin_authorized_at`, set `is_auth_token = false`, clear any pending plugin auth tokens (so plugin must request a fresh authorize flow). Do NOT set cooldown timestamp.
  - Effect: user can be re-authorized immediately via the normal authorize-email flow; no cooldown blocks issuance.
  - Use when: a user legitimately changes domain and needs immediate re-authorization, or the admin approves an ad-hoc domain change.

Behavior details (server-side)
- Database fields used:
  - `plugin_domain_hash` (string, nullable): server-calculated HMAC of normalized host using per-license secret.
  - `plugin_authorized_at` (timestamp, nullable): when email authorization occurred.
  - `is_auth_token` (bool): whether the user is authorized to receive tokens.
  - `plugin_auth_token` / `plugin_auth_token_expires_at`: one-time authorization tokens used by email flow.
  - `plugin_domain_reset_requested_at` (timestamp, nullable): when a cooldown reset was requested.
  - `plugin_domain_reset_count` (int): how many resets (useful for throttling/audit).

- Cooldown enforcement:
  - Default length: 30 days (hardcoded in current implementation).
  - While cooldown active, `POST /api/plugin/token` returns 403 and no email is sent.
  - Admin `Reset (immediate)` explicitly clears cooldown behavior so re-authorization can proceed immediately.

- Token issuance & validation changes:
  - JWTs are signed per-license using a `licenseSecret = HMAC(plugin_key, PLUGIN_JWT_SECRET)`.
  - Issued JWTs include `dh` (domain hash) claim when a `plugin_domain_hash` exists for the user.
  - On token issue/refresh, incoming domain (from `plugin_domain` param or `Origin` header) is normalized (lowercase, strip leading `www.`) and HMAC'ed with `licenseSecret` and compared to stored `plugin_domain_hash`.

Examples / recommended usage
- Scenario A: suspected compromise
  - Action: Admin clicks **Revoke**.
  - Result: Immediate token rejection; operator investigates. To restore, admin must `Restore` (clear `plugin_revoked_at`) after remediation.

- Scenario B: user migrates site and requests change but operator wants guardrails
  - Action: Admin chooses **Reset (cooldown)**.
  - Result: Domain binding is removed, but plugin cannot immediately reauthorize for 30 days; prevents repeated rapid changes or abuse. Admin can later perform **Reset (immediate)** if they choose to override.

- Scenario C: small, trusted change (e.g., dev wants immediate rebind)
  - Action: Admin chooses **Reset (immediate)**.
  - Result: Domain binding removed and user can reauthorize immediately via email flow.

Operational notes
- Display: admin UI shows masked `plugin_domain_hash` (first/last 6 chars) and offers both Reset buttons.
- Backfill: use `plugin:backfill-domain-hash` artisan command to populate `plugin_domain_hash` from `plugin_pending_domain` for existing users before enforcing new behavior.
- Config: cooldown length should be moved to config/env (e.g., `PLUGIN_DOMAIN_RESET_COOLDOWN_DAYS`) if you want to change it without code edits.

Auditing
- All reset and revoke actions should be logged (admin user id, timestamp, mode). The current implementation writes changes to the `users` row; consider adding an audit table or model events for fuller history.

Next steps (optional)
- Add UI indication of remaining cooldown time on the People page.
- Make cooldown length configurable via `config/plugin.php` and `.env`.
- Add tests for reset flows (cooldown and immediate) and for cooldown enforcement on `/api/plugin/token`.

---
Generated: automated doc saved in the repository.
