NestJS Profiler
Packages

nest-profiler-auth

Capture the authenticated user, roles and JWT claims in the Security panel.

@eleven-labs/nest-profiler-auth

@eleven-labs/nest-profiler-auth captures the authentication context (Passport user, JWT claims, roles) of the current execution and displays it in a Security panel.

Security panel — authenticated user, roles and decoded JWT claims with sensitive fields masked

Installation

pnpm add -D @eleven-labs/nest-profiler-auth

No additional peer dependencies beyond nestjs-cls (already required by @eleven-labs/nest-profiler).

Setup

profiling/profiling.module.ts
import { Module } from '@nestjs/common';
import { ProfilerModule } from '@eleven-labs/nest-profiler';
import { AuthCollectorModule } from '@eleven-labs/nest-profiler-auth';

@Module({
  imports: [
    ProfilerModule.forRoot({ isGlobal: true }),
    AuthCollectorModule.forRoot({ maskUserFields: ['password', 'refreshToken'] }),
  ],
})
export class ProfilingModule {}

ProfilingModule is the dev-only bundle loaded by main-dev.ts — see Enabling and disabling the profiler. If the profiler is installed as a production dependency behind the runtime gate, wrap the same call in ConditionalModule.registerWhen(..., isProfilerEnabled).

Authentication itself stays in your application: the guard (Passport or your own) that sets request.user lives in your production modules, and the collector reads what it leaves on the request.

What it collects

FieldDescription
isAuthenticatedtrue when request.user is populated (Passport)
userThe request.user object (with sensitive fields masked)
rolesuser.roles or user.role (normalized to array)
jwtClaimsDecoded JWT payload from Authorization: Bearer …

Automatic masking: Fields matching password|secret|key|token|credential are replaced with ***. Additional fields can be specified via maskUserFields.

Note: The JWT is decoded without verification (display only). Never rely on this data for security decisions.

Toolbar badge

Unauthenticated requests always show a compact anon. For authenticated requests, the badge content is configurable via the badge option (default: 'status'), so a long email no longer wraps the sidebar row — the full identity stays in the panel detail:

badgeAuthenticated badge
'status'A fixed, compact auth label (default) — mirrors anon.
'role'The first role (admin, user, …), falling back to auth.
'identifier'Legacy behaviour: username ?? email ?? sub ?? id, else auth.
AuthCollectorModule.forRoot({
  badge: 'role', // 'status' (default) | 'role' | 'identifier'
});

For full control, provide a badgeValue resolver — it takes precedence over badge, receives the collected SecurityContext, and may return null to hide the badge. It runs only for authenticated requests (unauthenticated stays anon):

AuthCollectorModule.forRoot({
  badgeValue: (security) => security.roles?.[0] ?? 'auth',
});

How it works

The collector reads request.user and the Authorization header from the current CLS context (set by the profiler middleware). It decodes the JWT payload using Buffer.from(payload, 'base64url') without any cryptographic verification.

Powered & maintained by

On this page