init
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
# Auth.js + Organization RBAC Guide
|
||||
|
||||
Use this guide when the task involves authentication, session-aware pages, or replacing Clerk-coupled access control.
|
||||
|
||||
## Target model
|
||||
|
||||
This repo should evolve toward an app-owned model:
|
||||
|
||||
- `user`: authenticated person
|
||||
- `organization`: active tenant or workspace
|
||||
- `membership`: join record between user and organization
|
||||
- `role`: coarse access level such as `owner`, `admin`, `member`
|
||||
- `permissions`: optional fine-grained capabilities
|
||||
|
||||
Auth.js authenticates the user. Your app owns the organization and RBAC data.
|
||||
|
||||
## Auth boundary
|
||||
|
||||
Prefer a single auth boundary that exports:
|
||||
|
||||
- Auth.js config
|
||||
- `auth()` session helper
|
||||
- provider definitions
|
||||
- callbacks that enrich the session with app-owned ids if needed
|
||||
|
||||
Typical locations:
|
||||
|
||||
- `auth.ts`
|
||||
- `src/auth.ts`
|
||||
|
||||
Keep usage consistent across:
|
||||
|
||||
- route handlers
|
||||
- protected server pages
|
||||
- shared server utilities
|
||||
|
||||
## Protection patterns
|
||||
|
||||
### Protected page
|
||||
|
||||
```tsx
|
||||
import { auth } from '@/auth';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
export default async function BillingPage() {
|
||||
const session = await auth();
|
||||
if (!session?.user) {
|
||||
redirect('/auth/sign-in');
|
||||
}
|
||||
|
||||
return <div>Protected page</div>;
|
||||
}
|
||||
```
|
||||
|
||||
### Protected route handler
|
||||
|
||||
```tsx
|
||||
import { NextResponse } from 'next/server';
|
||||
import { auth } from '@/auth';
|
||||
|
||||
export async function POST() {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ ok: true });
|
||||
}
|
||||
```
|
||||
|
||||
## Membership checks
|
||||
|
||||
Prefer a reusable server helper for membership resolution so page and API protection behave the same way.
|
||||
|
||||
Good responsibilities for a helper:
|
||||
|
||||
- require an authenticated session
|
||||
- look up the active organization
|
||||
- load the user's membership
|
||||
- optionally enforce role or permissions
|
||||
|
||||
Example shape:
|
||||
|
||||
```tsx
|
||||
export async function requireOrganizationAccess(options?: {
|
||||
role?: 'owner' | 'admin' | 'member';
|
||||
permission?: string;
|
||||
}) {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) throw new Error('Unauthorized');
|
||||
|
||||
const membership = await findActiveMembership(session.user.id);
|
||||
if (!membership) throw new Error('Organization membership required');
|
||||
|
||||
if (options?.role && membership.role !== options.role) {
|
||||
throw new Error('Forbidden');
|
||||
}
|
||||
|
||||
return { session, membership };
|
||||
}
|
||||
```
|
||||
|
||||
## Navigation migration
|
||||
|
||||
The current repo uses Clerk hooks in `src/hooks/use-nav.ts`. Treat this as legacy.
|
||||
|
||||
Target behavior:
|
||||
|
||||
- nav visibility comes from app-owned session or membership data
|
||||
- client rendering may consume a serialized access snapshot
|
||||
- server pages and route handlers still enforce real access independently
|
||||
|
||||
If the task touches navigation, prefer one of these approaches:
|
||||
|
||||
1. compute filtered nav on the server and pass it into layout state
|
||||
2. expose a lightweight session or membership snapshot to the client
|
||||
3. keep client filtering, but source it from app-owned data rather than Clerk hooks
|
||||
|
||||
## Plan and feature gates
|
||||
|
||||
Do not map old Clerk Billing language directly into Auth.js.
|
||||
|
||||
Instead:
|
||||
|
||||
- store plan state on `organizations`, `subscriptions`, or entitlement tables
|
||||
- expose a server helper such as `requirePlan('pro')`
|
||||
- keep the page or API gate server-side
|
||||
|
||||
If there is no billing provider yet, document it as a placeholder and do not over-promise implementation detail.
|
||||
|
||||
## Migration advice for this repo
|
||||
|
||||
Clerk hot spots currently include:
|
||||
|
||||
- `src/proxy.ts`
|
||||
- `src/hooks/use-nav.ts`
|
||||
- `src/components/layout/providers.tsx`
|
||||
- `src/components/layout/user-nav.tsx`
|
||||
- `src/components/layout/app-sidebar.tsx`
|
||||
- `src/app/dashboard/workspaces/**`
|
||||
- `src/app/dashboard/billing/page.tsx`
|
||||
|
||||
Migrate in this order when possible:
|
||||
|
||||
1. auth config and protected-route shell
|
||||
2. session-aware layout or providers
|
||||
3. shared membership and RBAC utilities
|
||||
4. page-level and route-level conversions
|
||||
5. navigation and UI cleanup
|
||||
Reference in New Issue
Block a user