Sensitive Action ReAuth

Feature Owner: scorevi (Sean Patrick Caintic)
Module: Auth & Security
Priority: P0
Sprint #12: Fully Implemented
Date: 2026-06-29


EXECUTIVE SUMMARY

What is this feature?
A time-bounded, single-use re-authentication system that requires admins to verify their identity (password or email confirmation) before performing destructive actions like deleting users, changing roles, transferring agency ownership, or modifying Gemini AI configuration.

Why does it matter?
Even an authenticated admin session can be hijacked (XSS, unattended computer). Without re-auth, a malicious actor with access to an active session could delete all users or transfer agency ownership without any additional verification.

What's the MVP scope?
issueReAuthToken() generates a UUID token with 5-minute TTL stored in admin_reauth_tokens. consumeReAuthToken() validates and marks as used (single-use). Token passed via request body (reauthToken field). ReAuthModal component (240 lines) auto-detects auth method. Protected endpoints: delete-user, change-role, agency delete/PATCH, gemini-config.


1. USER PAIN POINT & SOLUTION

Current State (Without Feature)

An admin signs in, leaves their computer unlocked, and someone else can access the admin panel and perform destructive actions without any additional verification.

Pain Point

Emotional: Anxiety about session hijacking — especially for admins with full platform access.
Functional: No secondary verification barrier for destructive actions.
Business Impact: Catastrophic data loss risk. GDPR/compliance violation risk from unauthorized data modification.

Future State (With Feature)

Before any destructive action, the admin must re-verify their identity. A 5-minute token is issued and consumed. After use, the token is invalidated. Audit logs track all re-auth attempts.

Marketing Hook

"Double-check before you wreck. Re-authentication protects what matters."


2. 4D FRAMEWORK MAPPINGDiagnose

N/A — security infrastructure.

Design

N/A — security infrastructure.

Develop

N/A — security infrastructure.

Deliver

N/A — security infrastructure.


3. USER FLOWS

Entry Point

Admin clicks a destructive action button (e.g., "Delete User", "Change Role", "Delete Agency", "Transfer Ownership", or saves Gemini config).

Success Criteria

Admin successfully re-authenticates, receives a 5-minute token, and the protected action executes. Token is consumed (single-use) and cannot be reused.

Main Flow (Happy Path)

  1. Admin initiates a protected action (e.g., delete user).

  2. Frontend calls GET /api/admin/reauth to detect available auth methods.

  3. ReAuthModal opens, displaying password or email confirmation prompt.

  4. Admin enters password (or confirms email).

  5. Frontend calls POST /api/admin/reauth with credentials.

  6. Server validates: non-admin → 403, wrong password → 401, email mismatch → 401.

  7. On success: issueReAuthToken() generates UUID token, stored in admin_reauth_tokens with 5-minute TTL.

  8. Response returns { token, expiresInSeconds: 300 }.

  9. Frontend includes token as reauthToken in the destructive action's request body.

  10. Server calls consumeReAuthToken(): validates token exists, belongs to requesting admin, not expired, not used.

  11. Server marks token as used = true.

  12. Destructive action executes. Audit log entry written.

Edge Cases

  • Token expired: consumeReAuthToken returns 403 "Re-authentication token has expired. Please re-authenticate."

  • Token already used: Returns 403 "Re-authentication token has already been used."

  • Wrong admin: Token belongs to Admin A, but Admin B tries to use it → 403.

  • DB error persisting token: issueReAuthToken throws "Could not issue re-authentication token".

  • DB error consuming token: consumeReAuthToken fails to mark as used → 403 "Failed to validate re-authentication token".

Decision Points

  • IF user is not an admin → 403 ApiResponseHelper.forbidden().

  • IF password is wrong → 401 ApiResponseHelper.unauthorized().

  • IF email doesn't match → 401 ApiResponseHelper.unauthorized().

  • IF token expired (now > expires_at) → 403 AuthorizationError.

  • IF token already used (used === true) → 403 AuthorizationError.


4. INFORMATION ARCHITECTURE

Primary Information (Always visible)

  • ReAuthModal with password field or email confirmation prompt.

  • Auth method indicator (auto-detected via GET /api/admin/reauth).

Secondary Information

  • "Action requires re-authentication" explanatory text.

  • Token TTL countdown (if shown in future UI).

Actions

Primary CTA: "Confirm" button to submit credentials.
Secondary Actions: "Cancel" button to abort the destructive action.


5. WIREFRAMES

[Excluded — existing UI: components/admin/ReAuthModal.tsx (240 lines)]

6. WIREFLOWS

Excluded.

7. PROTOTYPE

[Excluded — existing implementation]


8. BACKEND SCHEMA

Database Tables

admin_reauth_tokens:

Column

Type

Description

id

(auto)

Primary key

token

TEXT NOT NULL UNIQUE

UUID v4 token (not UUID DB type)

admin_clerk_id

TEXT

Clerk ID of the admin

expires_at

TIMESTAMPTZ

Token expiry (issued_at + 5 min)

used

BOOLEAN

Whether token has been consumed (single-use)

ip_address

TEXT (nullable)

Client IP for audit trail

created_at

TIMESTAMPTZ

Token creation time

audit_logs:

Column

Type

Description

id

(auto)

Primary key

user_id

UUID

References app_users(id)

action

VARCHAR(100)

Action performed

entity_type

VARCHAR(50)

Type of entity affected

entity_id

UUID

ID of entity affected

user_agent

TEXT

Client user agent string


9. API ENDPOINTS

Method

Endpoint

Auth

File

Description

GET

/api/admin/reauth

Admin

app/api/admin/reauth/route.ts (193 lines)

Auto-detects available auth methods (password or email confirmation)

POST

/api/admin/reauth

Admin

app/api/admin/reauth/route.ts (193 lines)

Validates credentials, returns { token, expiresInSeconds: 300 }

Protected endpoints requiring reauthToken in request body:

  • POST /api/admin/delete-user — user deletion

  • POST /api/admin/change-role — role change

  • DELETE /api/admin/agencies/[id] — agency deletion

  • PATCH /api/admin/agencies/[id] — ownership transfer

  • POST (gemini-config server action) — AI configuration changes

Response shapes:

  • Success (POST reauth): { token: string, expiresInSeconds: 300 }

  • Non-admin access: 403 ApiResponseHelper.forbidden()

  • Wrong password: 401 ApiResponseHelper.unauthorized()

  • Email mismatch: 401 ApiResponseHelper.unauthorized()


10. DATA REQUIREMENTS

Frontend Needs

  • ReAuthModal component (components/admin/ReAuthModal.tsx, 240 lines) for credential input.

  • Token storage in component state (passed to subsequent API call).

  • Auto-detection of auth method via GET /api/admin/reauth.

API Calls Frontend Will Make

  1. GET /api/admin/reauth → determine auth method (password or email confirmation).

  2. POST /api/admin/reauth with credentials → receive token.

  3. Protected action API call with { reauthToken, ...actionPayload } → action executes.

Caching Strategy

Token is stored in memory (React state) and consumed immediately. No caching — single-use by design.


11. PERFORMANCE CONSIDERATIONS

Database Optimization

  • admin_reauth_tokens.token has UNIQUE constraint — indexed for fast lookup.

  • Token consumption is a single UPDATE by primary key.

API Response Time

  • issueReAuthToken: <50ms (single INSERT).

  • consumeReAuthToken: <100ms (SELECT + UPDATE).

  • Reauth API: <200ms (credential validation + token issue).


12. SECURITY & AUTHORIZATION

Who can access this feature?

Only admin users. Non-admin requests return 403.

Authorization Logic

  • Reauth endpoint: non-admin → 403 ApiResponseHelper.forbidden().

  • Token validation: adminClerkId must match the requesting admin → otherwise 403.

  • Token is single-use: marked used = true on first consumption.

  • Token TTL: REAUTH_TTL_MINUTES = 5 (300 seconds).

  • Token generated via randomUUID() (cryptographically secure).

  • Token passed via request body (reauthToken field), NOT header.

Data Validation

  • Password/email validation against Clerk (server-side, never exposed to client).

  • Token UUID format validation via database UNIQUE constraint + exact match query.


13. ERROR HANDLING

Error

Response

Non-admin accesses reauth endpoint

403 ApiResponseHelper.forbidden()

Wrong password

401 ApiResponseHelper.unauthorized()

Email mismatch

401 ApiResponseHelper.unauthorized()

Token not found

403 AuthorizationError("Invalid re-authentication token")

Token belongs to different admin

403 AuthorizationError("Re-authentication token does not belong to this admin")

Token already used

403 AuthorizationError("Re-authentication token has already been used")

Token expired

403 AuthorizationError("Re-authentication token has expired. Please re-authenticate.")

Failed to persist token

Error("Could not issue re-authentication token")

Failed to mark token used

403 AuthorizationError("Failed to validate re-authentication token")


14. TESTING CHECKLIST

Happy Path
□ Admin re-authenticates with correct password → token issued → protected action uses token → action succeeds → token marked used.
□ Admin re-authenticates via email confirmation → token issued → action succeeds.

Edge Cases
□ Non-admin accesses reauth endpoint → 403.
□ Wrong password → 401.
□ Attempt to reuse consumed token → 403 "already been used".
□ Attempt to use expired token → 403 "has expired".
□ Attempt to use another admin's token → 403 "does not belong to this admin".
□ DB insert error during token issue → Error thrown, 500 returned.
□ DB update error during token consumption → 403.
□ Token used within 5-minute window → valid.
□ Token used after 5 minutes → expired.


15. OPEN QUESTIONS

  • Should the 5-minute TTL be configurable per environment?

  • Should reauth be required for additional admin actions (e.g., changing system config)?

  • Should audit logs include the reauth token ID for traceability?


16. OUT OF SCOPE (v1.1+)

  • TOTP / authenticator app-based re-authentication.

  • Biometric re-authentication (WebAuthn).

  • Configurable reauth TTL per action type.

  • Reauth requirement for non-admin roles (e.g., agency owners).


17. SUCCESS METRICS

  • 100% of protected destructive actions require valid reauth token.

  • Zero token reuse incidents.

  • <2 second reauth flow completion time.


18. DEPENDENCIES

This feature depends on:

  • Clerk for admin identity verification (password/email validation).

  • lib/auth/reauth.ts (94 lines): issueReAuthToken(), consumeReAuthToken().

  • lib/auth/authenticate.ts: AuthorizationError class.

  • admin_reauth_tokens table for token persistence.

  • audit_logs table for action logging.

  • components/admin/ReAuthModal.tsx (240 lines) for UI.

These features depend on this:

  • Admin user management (delete, role change).

  • Agency management (delete, ownership transfer).

  • Gemini AI configuration.


19. TIMELINE & OWNERSHIP

  • Implemented: Sprint 0 (foundational).

  • Owner: scorevi (Sean Patrick Caintic)


Document Version

1.0 - Initial version - 2026-06-29 08:06 UTC

1.1 - Added Document Version section and update author to have full name - 2026-06-29 08:41 UTC


Was this article helpful?