Auth & Permissions

JwtAuthGuard

Add @UseGuards(JwtAuthGuard) to any endpoint that requires authentication. It will:

  1. Extract JWT from Authorization: Bearer {token}
  2. Validate the token
  3. Set req.user (user info)
  4. If x-tenant-id header is present, verify membership in tenant_members and set req.tenant

Request Context

// req.user — User info (from JWT)
{
  user_id: string    // User ID
  email: string      // Email
  role: string       // System role (from users table)
  verified: boolean  // Email verified
}

// req.tenant — Organization info (from x-tenant-id + DB verification)
{
  id: string         // Organization ID
  role: string       // Role in organization (from tenant_members table)
}

Two Types of Roles

RoleSourceFieldPurpose
System roleusers.rolereq.user.roleDistinguish admin from regular users
Org roletenant_members.rolereq.tenant.roleDistinguish permissions within an org

Permission Check Examples

Check if Organization Owner

private async requireOwner(tenantId: string, userId: string) {
  const member = await this.memberService.isMember(tenantId, userId)
  if (!member || member.role !== "owner") {
    throw new ForbiddenException("Only owner can perform this action")
  }
}

// Usage
@Post(":tenant_id/update")
async update(@Param("tenant_id") tenantId: string, @Req() req: CustomRequest, ...) {
  await this.requireOwner(tenantId, req.user.user_id)
  // ...
}

Check Custom Role

@Post("admin-action")
async adminAction(@Req() req: CustomRequest, @Res() res: Response) {
  const tenantRole = req.tenant?.role
  if (tenantRole !== 'admin' && tenantRole !== 'owner') {
    throw new ForbiddenException("Requires admin or owner role")
  }
  // ...
}

Check System Admin

if (req.user.role !== 'owner') {
  throw new ForbiddenException("Requires system admin")
}

Public Endpoints (No Auth)

Simply omit @UseGuards(JwtAuthGuard):

@Controller({ version: "1", path: "public" })
export class PublicController {
  @Get("health")
  health() {
    return { status: "ok" }
  }
}