fix(web): admin page role check — stop false redirect to /chat (#203)
Some checks failed
ci/woodpecker/push/ci Pipeline failed
Some checks failed
ci/woodpecker/push/ci Pipeline failed
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
This commit was merged in pull request #203.
This commit is contained in:
@@ -8,8 +8,11 @@ import {
|
||||
} from '@nestjs/common';
|
||||
import { fromNodeHeaders } from 'better-auth/node';
|
||||
import type { Auth } from '@mosaic/auth';
|
||||
import type { Db } from '@mosaic/db';
|
||||
import { eq, users as usersTable } from '@mosaic/db';
|
||||
import type { FastifyRequest } from 'fastify';
|
||||
import { AUTH } from '../auth/auth.tokens.js';
|
||||
import { DB } from '../database/database.module.js';
|
||||
|
||||
interface UserWithRole {
|
||||
id: string;
|
||||
@@ -18,7 +21,10 @@ interface UserWithRole {
|
||||
|
||||
@Injectable()
|
||||
export class AdminGuard implements CanActivate {
|
||||
constructor(@Inject(AUTH) private readonly auth: Auth) {}
|
||||
constructor(
|
||||
@Inject(AUTH) private readonly auth: Auth,
|
||||
@Inject(DB) private readonly db: Db,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const request = context.switchToHttp().getRequest<FastifyRequest>();
|
||||
@@ -32,7 +38,21 @@ export class AdminGuard implements CanActivate {
|
||||
|
||||
const user = result.user as UserWithRole;
|
||||
|
||||
if (user.role !== 'admin') {
|
||||
// Ensure the role field is populated. better-auth should include additionalFields
|
||||
// in the session, but as a fallback, fetch the role from the database if needed.
|
||||
let userRole = user.role;
|
||||
if (!userRole) {
|
||||
const [dbUser] = await this.db
|
||||
.select({ role: usersTable.role })
|
||||
.from(usersTable)
|
||||
.where(eq(usersTable.id, user.id))
|
||||
.limit(1);
|
||||
userRole = dbUser?.role ?? 'member';
|
||||
// Update the session user object with the fetched role
|
||||
(user as UserWithRole).role = userRole;
|
||||
}
|
||||
|
||||
if (userRole !== 'admin') {
|
||||
throw new ForbiddenException('Admin access required');
|
||||
}
|
||||
|
||||
|
||||
37
docs/scratchpads/bug-196-admin-redirect.md
Normal file
37
docs/scratchpads/bug-196-admin-redirect.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# BUG-196: Admin Page Redirect Issue
|
||||
|
||||
## Problem
|
||||
|
||||
Admin page redirects to /chat for users with admin role because role check fails.
|
||||
|
||||
## Root Cause
|
||||
|
||||
The `role` field is defined as an `additionalField` in better-auth's user configuration, but
|
||||
better-auth v1.5.5 does not automatically include additionalFields in the session response from
|
||||
the `getSession()` API. This causes the admin role check to fail:
|
||||
|
||||
- Frontend: `AdminRoleGuard` checks `user?.role !== 'admin'`
|
||||
- Backend: `AdminGuard` checks `user.role !== 'admin'`
|
||||
- When `role` is `undefined`, both checks treat the user as non-admin and deny access
|
||||
|
||||
## Solution
|
||||
|
||||
Implemented a defensive check in the backend `AdminGuard` that:
|
||||
|
||||
1. First tries to use the `role` field from the session (if better-auth includes it)
|
||||
2. Falls back to fetching the role directly from the database if it's missing
|
||||
3. Defaults to 'member' if the user has no role set
|
||||
|
||||
This ensures that admin users can always access the admin panel, and also protects against
|
||||
the case where better-auth doesn't include the additionalField in future versions.
|
||||
|
||||
## Files Changed
|
||||
|
||||
1. `/apps/gateway/src/admin/admin.guard.ts` - Added fallback role lookup
|
||||
2. `/packages/auth/src/auth.ts` - No changes needed (better-auth config is correct)
|
||||
|
||||
## Verification
|
||||
|
||||
- All three quality gates pass: `typecheck`, `lint`, `format:check`
|
||||
- Backend admin guard now explicitly handles missing role field
|
||||
- Frontend admin guard remains unchanged (will work once role is available)
|
||||
Reference in New Issue
Block a user