Auth/Security profiling
Capture the authenticated user, roles and JWT claims in the profiler's Security panel with nest-profiler-auth.
This tutorial shows how to add the auth collector to capture authentication context (Passport user, JWT claims, roles) in the Security panel.
Prerequisites
@eleven-labs/nest-profilerinstalled and configured- Passport (or any auth strategy that populates
request.user)
Step 1 - Install the package
pnpm add @eleven-labs/nest-profiler-auth@alphaStep 2 - Register the module
import { ConditionalModule } from '@nestjs/config';
import { ProfilerModule } from '@eleven-labs/nest-profiler';
import { AuthCollectorModule } from '@eleven-labs/nest-profiler-auth';
const isProfilerEnabled = (env: NodeJS.ProcessEnv) => env['PROFILER_ENABLED'] === 'true';
@Module({
imports: [
ConditionalModule.registerWhen(ProfilerModule.forRoot({ isGlobal: true }), isProfilerEnabled),
ConditionalModule.registerWhen(
AuthCollectorModule.forRoot({ maskUserFields: ['password', 'refreshToken'] }),
isProfilerEnabled,
),
],
})
export class AppModule {}Step 3 - Set up authentication
The auth collector reads request.user automatically. Any guard or middleware that sets request.user will work - Passport, JWT guards, API key guards, etc.
Example with a minimal JWT guard:
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
@Injectable()
export class JwtAuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
const authHeader = request.headers['authorization'];
if (authHeader?.startsWith('Bearer ')) {
try {
const [, payload] = authHeader.slice(7).split('.');
request.user = JSON.parse(Buffer.from(payload, 'base64url').toString());
} catch {
/* invalid JWT */
}
}
return true; // always allow - auth is for display only
}
}Apply the guard globally or per-route:
import { APP_GUARD } from '@nestjs/core';
providers: [{ provide: APP_GUARD, useClass: JwtAuthGuard }],Step 4 - Test it
# Without auth - Security tab shows "Anonymous"
curl http://localhost:3000/profile
# With a JWT - Security tab shows user info and claims
TOKEN=$(curl -s "http://localhost:3000/api/v1/auth/token" | jq -r .token)
curl -H "Authorization: Bearer $TOKEN" http://localhost:3000/profileOpen /_profiler/{token} → Security tab.
Authenticated profile shows:
- Status:
Authenticated - User:
{ sub: "42", username: "demo_user", email: "demo@example.com" } - Roles:
["user"] - JWT Claims: full decoded payload
The toolbar badge shows the username (e.g., demo_user) or anon for unauthenticated requests.
Masking
Fields matching /password|secret|key|token|credential/i are automatically replaced with ***. Additional fields can be masked via maskUserFields:
AuthCollectorModule.forRoot({
maskUserFields: ['refreshToken', 'apiKey'],
});The JWT is decoded without signature verification - the displayed claims are for debugging only. Never rely on this data for authorization decisions in your application code.
Driving options from ConfigService
Use forRootAsync() to resolve maskUserFields from ConfigService (or any provider), gated per environment with ConditionalModule — the recommended way (for the enabled flag, see Enabling and disabling the profiler):
import { ConditionalModule, ConfigService } from '@nestjs/config';
ConditionalModule.registerWhen(
AuthCollectorModule.forRootAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
maskUserFields: config.get<string[]>('profiler.maskUserFields') ?? [
'password',
'refreshToken',
],
}),
}),
isProfilerEnabled,
);How it works
The collector reads request.user and the Authorization header from the current CLS context and decodes the JWT payload (no signature verification) before applying the masking rules. See How it works on the package page.