Authorization Implementation Plan for Next.js App
✅ FINAL AUTHORIZATION & LICENSED SESSION SCHEMA
(Authoritative Execution Plan for Next.js + C# + Firebase)
1. Scope & Objectives
This plan defines authentication, authorization (RBAC), and license enforcement for the Next.js mobile frontend while preserving:
- Existing MS SQL role tables
- Existing backend authorization logic
- Multi-tenant (database-per-tenant) isolation
- Capacity planning guarantees
- Zero-crash behavior
- Backward compatibility with Blazor
2. Non-Negotiable Principles (Must Be Followed)
-
Backend is the sole authority for authorization and licensing
-
Frontend never decides access — it only reflects backend decisions
-
Every protected API enforces permission checks
-
Session ≠ JWT
- JWT proves identity
- Session proves license usage
-
Sessions are time-bound leases, not permanent locks
-
No client-side storage (localStorage) is authoritative
3. Data Model (Required Tables)
3.1 UserLicenses
UserLicenses
------------
UserId
MaxConcurrentSessions -- typically 13.2 UserSessions
UserSessions
------------
SessionId (GUID, PK)
UserId
FirebaseUid
TenantId
DeviceId
IssuedAt
LastSeenAt
IsRevoked (bit)Derived rule (important):
Session is ACTIVE if:
IsRevoked = 0
AND LastSeenAt >= (NOW - IdleTimeout)IdleTimeout (recommended): 10 minutes
4. Authentication Flow (Firebase)
-
User logs in via Firebase Auth (email/password or provider)
-
Firebase issues JWT (identity only)
-
Next.js sends JWT to backend
-
Backend validates JWT
-
Backend resolves:
- FirebaseUid
- TenantContext
- Internal UserId
Authentication ends here.
5. Licensed Session Creation Flow (Critical)
5.1 Login Handshake Endpoint
POST /api/auth/session/start
Authorization: Bearer <Firebase JWT>5.2 Backend Logic (Authoritative)
resolve UserId + TenantContext
activeSessions =
SELECT *
FROM UserSessions
WHERE UserId = @UserId
AND IsRevoked = 0
AND LastSeenAt >= NOW - IdleTimeout
if activeSessions.count < MaxConcurrentSessions:
create new session
return SessionToken
else:
return 409 CONFLICT
with payload:
{
"reason": "ACTIVE_SESSION_EXISTS",
"sessions": [device info, lastSeen]
}6. “Already Signed In on Another Device” Handling
6.1 Frontend UX (Next.js)
If backend returns ACTIVE_SESSION_EXISTS:
Display modal:
You are already signed in on another device. Continuing will sign you out from the other device.
Buttons:
- Continue & Sign Out Other Device
- Cancel
6.2 Takeover Endpoint (Recommended Default)
POST /api/auth/session/takeover
Authorization: Bearer <Firebase JWT>Backend action:
revoke all active sessions for UserId
create new session
return new SessionTokenThis guarantees:
- No lockouts
- No waiting for idle timeout
- Clean license enforcement
7. Session Token Handling (Secure)
-
SessionToken is:
- Opaque GUID
- Backend-issued
-
Stored as:
- HTTP-only cookie (preferred)
- OR encrypted server-only storage
❌ Never store in localStorage ❌ Never trust client-provided session IDs
8. Session Heartbeat (No Lockout Guarantee)
8.1 Automatic Heartbeat
Every authenticated API call must:
UPDATE UserSessions
SET LastSeenAt = NOW
WHERE SessionId = @SessionIdOptional lightweight endpoint:
POST /api/auth/session/pingCalled every 2–5 minutes.
9. Authorization (RBAC) — Backend Only
9.1 Existing Role Logic (Reused)
Use existing tables and logic:
user_roles_link
roles
featuresExisting backend method remains authoritative:
HasAccess(featureCode)9.2 Enforcement Rule (Mandatory)
Every protected API must include:
if (!HasAccess("FeatureCode"))
return Forbid();Frontend checks do not replace this.
10. Frontend Permission Awareness (UX Only)
10.1 Permissions Endpoint
GET /api/auth/my-permissionsReturns:
{
"MemberMstDetails": true,
"MemberMstReport": false
}Derived from backend role logic.
10.2 Usage in Next.js
-
Used to:
- Hide menu items
- Disable buttons
- Control routing
-
NOT used as security boundary
11. Request Authorization Pipeline (Backend)
Order matters:
- JWT validation
- TenantContext resolution
- Session validation (active + heartbeat)
- Authorization (RBAC)
- Controller logic
- Repository execution
If any step fails → 401 or 403, never 500
12. Failure Modes (Defined, Predictable)
| Scenario | Response |
|---|---|
| Invalid JWT | 401 |
| No active session | 401 |
| Session expired | 401 |
| Role missing | 403 |
| Tenant invalid | 401 |
| Session takeover | 200 |
Backend must never crash due to auth/session issues.
13. Backward Compatibility (Blazor)
-
Blazor continues using:
- Existing role checks
- Existing auth
-
Session enforcement can be:
- Introduced later
- Or applied uniformly once stable
No breaking change required.
14. Explicit Anti-Patterns (DO NOT IMPLEMENT)
❌ Client-side RBAC enforcement ❌ localStorage session validation ❌ BrowserSessionId comparisons ❌ Trusting JWT claims for licensing ❌ Blocking login without takeover option
15. One-Line Contract (Give This to Antigravity)
Authentication proves identity. Authorization proves permission. Sessions enforce licensing. Only the backend decides.
16. Execution Order (Recommended)
- Implement UserSessions + UserLicenses tables
- Implement
/session/startand/session/takeover - Add heartbeat update on API calls
- Enforce RBAC inside APIs
- Add permissions endpoint for Next.js
- Remove legacy BrowserSessionId logic
✅ This plan:
- Solves credential sharing
- Prevents capacity overruns
- Avoids lockouts
- Works with Firebase + JWT
- Matches enterprise ERP behavior
You can now hand this directly to Antigravity and say:
“Implement exactly this. Do not invent alternatives.”