add more logs

This commit is contained in:
LeoMortari
2025-09-15 01:15:29 -03:00
parent 9b3675a10d
commit bbb6c97408
3 changed files with 96 additions and 34 deletions

View File

@@ -33,8 +33,10 @@
"cross-env": "10.0.0",
"dayjs": "1.11.13",
"jwks-rsa": "3.2.0",
"nestjs-pino": "4.4.0",
"passport": "0.7.0",
"passport-jwt": "4.0.1",
"pino-http": "10.5.0",
"reflect-metadata": "0.2.2",
"rxjs": "7.8.1"
},

View File

@@ -52,41 +52,70 @@ export class KeycloakJwtStrategy extends PassportStrategy(Strategy, 'jwt') {
private readonly logger = new Logger(KeycloakJwtStrategy.name);
validate(payload: JwtPayload): JwtPayload {
this.logger.debug(
`JWT Payload received: ${JSON.stringify(payload, null, 2)}`,
try {
// Basic JWT info
this.logger.verbose('=== JWT Validation Start ===');
// Token metadata
this.logger.verbose(`Subject (sub): ${payload.sub}`);
this.logger.verbose(`Issuer (iss): ${payload.iss}`);
this.logger.verbose(`Audience (aud): ${JSON.stringify(payload.aud)}`);
this.logger.verbose(
`Issued At (iat): ${new Date(payload.iat * 1000).toISOString()}`,
);
this.logger.verbose(
`Expiration (exp): ${new Date(payload.exp * 1000).toISOString()}`,
);
// Log important JWT claims
this.logger.debug(`JWT Subject (sub): ${payload.sub}`);
this.logger.debug(`JWT Issuer (iss): ${payload.iss}`);
this.logger.debug(`JWT Audience (aud): ${JSON.stringify(payload.aud)}`);
this.logger.debug(
`JWT Expiration (exp): ${new Date(payload.exp * 1000).toISOString()}`,
);
this.logger.debug(
`JWT Issued At (iat): ${new Date(payload.iat * 1000).toISOString()}`,
// User info
this.logger.verbose('--- User Info ---');
this.logger.verbose(`Email: ${payload.email || 'N/A'}`);
this.logger.verbose(`Username: ${payload.preferred_username || 'N/A'}`);
this.logger.verbose(
`Name: ${payload.given_name || ''} ${payload.family_name || ''}`.trim() ||
'N/A',
);
// Log user info
this.logger.debug(`User email: ${payload.email}`);
this.logger.debug(`Username: ${payload.preferred_username}`);
// Log roles
this.logger.debug(
`Realm access roles: ${JSON.stringify(payload.realm_access?.roles || [])}`,
);
if (payload.resource_access) {
this.logger.debug('Resource access:');
Object.entries(payload.resource_access).forEach(([resource, data]) => {
this.logger.debug(` ${resource}: ${JSON.stringify(data.roles || [])}`);
// Realm roles
this.logger.verbose('--- Realm Access ---');
if (payload.realm_access?.roles?.length) {
payload.realm_access.roles.forEach((role: string) => {
this.logger.verbose(`- ${role}`);
});
} else {
this.logger.verbose('No realm roles found');
}
if (payload.exp < Date.now() / 1000) {
// Resource access
this.logger.verbose('--- Resource Access ---');
if (payload.resource_access) {
Object.entries(payload.resource_access).forEach(([resource, data]) => {
if (data?.roles?.length) {
this.logger.verbose(`${resource} roles:`);
data.roles.forEach((role: string) => {
this.logger.verbose(` - ${role}`);
});
}
});
} else {
this.logger.verbose('No resource access found');
}
// Token expiration check
const now = Math.floor(Date.now() / 1000);
if (payload.exp < now) {
const minutesAgo = Math.round((now - payload.exp) / 60);
this.logger.warn(`Token expired ${minutesAgo} minutes ago`);
throw new UnauthorizedException('Token expirado');
}
this.logger.verbose('=== JWT Validation Successful ===');
return payload;
} catch (error: unknown) {
const errorMessage = error instanceof Error ? error.stack : String(error);
this.logger.error('JWT Validation Error:', errorMessage);
throw error;
}
return payload;
}
}

View File

@@ -1,13 +1,44 @@
import { ClassSerializerInterceptor } from '@nestjs/common';
import {
ClassSerializerInterceptor,
Logger,
ValidationPipe,
} from '@nestjs/common';
import { NestFactory, Reflector } from '@nestjs/core';
import { AppModule } from './app.module';
import { Logger as PinoLogger } from 'nestjs-pino';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const app = await NestFactory.create(AppModule, {
bufferLogs: true,
logger: ['error', 'warn', 'log', 'debug', 'verbose'],
});
const reflector = app.get(Reflector);
const logger = new Logger('Bootstrap');
const pinoLogger = app.get(PinoLogger);
app.useLogger(pinoLogger);
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
transform: true,
}),
);
app.useGlobalInterceptors(new ClassSerializerInterceptor(reflector));
await app.listen(process.env.PORT ?? 3000);
app.enableCors();
const port = process.env.PORT ?? 3000;
await app.listen(port);
logger.log(`Application is running on port: ${port}`);
logger.debug(`Debug mode is enabled`);
}
void bootstrap();
bootstrap().catch((err) => {
const logger = new Logger('Bootstrap');
logger.error('Failed to start application', err);
process.exit(1);
});