feat: auth & admin

This commit is contained in:
2026-06-03 10:41:53 +03:00
parent 612d0f0125
commit 7dc59fb3c4
120 changed files with 4683 additions and 2159 deletions
@@ -16,80 +16,80 @@ Next.js documentation explicitly states: "Treat Server Actions with the same sec
**Incorrect (no authentication check):**
```typescript
'use server'
'use server';
export async function deleteUser(userId: string) {
// Anyone can call this! No auth check
await db.user.delete({ where: { id: userId } })
return { success: true }
await db.user.delete({ where: { id: userId } });
return { success: true };
}
```
**Correct (authentication inside the action):**
```typescript
'use server'
'use server';
import { verifySession } from '@/lib/auth'
import { unauthorized } from '@/lib/errors'
import { verifySession } from '@/lib/auth';
import { unauthorized } from '@/lib/errors';
export async function deleteUser(userId: string) {
// Always check auth inside the action
const session = await verifySession()
const session = await verifySession();
if (!session) {
throw unauthorized('Must be logged in')
throw unauthorized('Must be logged in');
}
// Check authorization too
if (session.user.role !== 'admin' && session.user.id !== userId) {
throw unauthorized('Cannot delete other users')
throw unauthorized('Cannot delete other users');
}
await db.user.delete({ where: { id: userId } })
return { success: true }
await db.user.delete({ where: { id: userId } });
return { success: true };
}
```
**With input validation:**
```typescript
'use server'
'use server';
import { verifySession } from '@/lib/auth'
import { z } from 'zod'
import { verifySession } from '@/lib/auth';
import { z } from 'zod';
const updateProfileSchema = z.object({
userId: z.string().uuid(),
name: z.string().min(1).max(100),
email: z.string().email()
})
email: z.string().email(),
});
export async function updateProfile(data: unknown) {
// Validate input first
const validated = updateProfileSchema.parse(data)
const validated = updateProfileSchema.parse(data);
// Then authenticate
const session = await verifySession()
const session = await verifySession();
if (!session) {
throw new Error('Unauthorized')
throw new Error('Unauthorized');
}
// Then authorize
if (session.user.id !== validated.userId) {
throw new Error('Can only update own profile')
throw new Error('Can only update own profile');
}
// Finally perform the mutation
await db.user.update({
where: { id: validated.userId },
data: {
name: validated.name,
email: validated.email
}
})
return { success: true }
email: validated.email,
},
});
return { success: true };
}
```