add more logs
This commit is contained in:
@@ -33,8 +33,10 @@
|
|||||||
"cross-env": "10.0.0",
|
"cross-env": "10.0.0",
|
||||||
"dayjs": "1.11.13",
|
"dayjs": "1.11.13",
|
||||||
"jwks-rsa": "3.2.0",
|
"jwks-rsa": "3.2.0",
|
||||||
|
"nestjs-pino": "4.4.0",
|
||||||
"passport": "0.7.0",
|
"passport": "0.7.0",
|
||||||
"passport-jwt": "4.0.1",
|
"passport-jwt": "4.0.1",
|
||||||
|
"pino-http": "10.5.0",
|
||||||
"reflect-metadata": "0.2.2",
|
"reflect-metadata": "0.2.2",
|
||||||
"rxjs": "7.8.1"
|
"rxjs": "7.8.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -52,41 +52,70 @@ export class KeycloakJwtStrategy extends PassportStrategy(Strategy, 'jwt') {
|
|||||||
private readonly logger = new Logger(KeycloakJwtStrategy.name);
|
private readonly logger = new Logger(KeycloakJwtStrategy.name);
|
||||||
|
|
||||||
validate(payload: JwtPayload): JwtPayload {
|
validate(payload: JwtPayload): JwtPayload {
|
||||||
this.logger.debug(
|
try {
|
||||||
`JWT Payload received: ${JSON.stringify(payload, null, 2)}`,
|
// 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
|
// User info
|
||||||
this.logger.debug(`JWT Subject (sub): ${payload.sub}`);
|
this.logger.verbose('--- User Info ---');
|
||||||
this.logger.debug(`JWT Issuer (iss): ${payload.iss}`);
|
this.logger.verbose(`Email: ${payload.email || 'N/A'}`);
|
||||||
this.logger.debug(`JWT Audience (aud): ${JSON.stringify(payload.aud)}`);
|
this.logger.verbose(`Username: ${payload.preferred_username || 'N/A'}`);
|
||||||
this.logger.debug(
|
this.logger.verbose(
|
||||||
`JWT Expiration (exp): ${new Date(payload.exp * 1000).toISOString()}`,
|
`Name: ${payload.given_name || ''} ${payload.family_name || ''}`.trim() ||
|
||||||
);
|
'N/A',
|
||||||
this.logger.debug(
|
|
||||||
`JWT Issued At (iat): ${new Date(payload.iat * 1000).toISOString()}`,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Log user info
|
// Realm roles
|
||||||
this.logger.debug(`User email: ${payload.email}`);
|
this.logger.verbose('--- Realm Access ---');
|
||||||
this.logger.debug(`Username: ${payload.preferred_username}`);
|
if (payload.realm_access?.roles?.length) {
|
||||||
|
payload.realm_access.roles.forEach((role: string) => {
|
||||||
// Log roles
|
this.logger.verbose(`- ${role}`);
|
||||||
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 || [])}`);
|
|
||||||
});
|
});
|
||||||
|
} 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');
|
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;
|
return payload;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
src/main.ts
39
src/main.ts
@@ -1,13 +1,44 @@
|
|||||||
import { ClassSerializerInterceptor } from '@nestjs/common';
|
import {
|
||||||
|
ClassSerializerInterceptor,
|
||||||
|
Logger,
|
||||||
|
ValidationPipe,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { NestFactory, Reflector } from '@nestjs/core';
|
import { NestFactory, Reflector } from '@nestjs/core';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
|
import { Logger as PinoLogger } from 'nestjs-pino';
|
||||||
|
|
||||||
async function bootstrap() {
|
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 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));
|
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);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user