63 lines
1.6 KiB
TypeScript
63 lines
1.6 KiB
TypeScript
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
|
import { PassportStrategy } from '@nestjs/passport';
|
|
import { ExtractJwt, Strategy } from 'passport-jwt';
|
|
|
|
import * as jwksRsa from 'jwks-rsa';
|
|
|
|
export type JwtAudience = string | string[] | undefined;
|
|
export interface JwtRealmAccess {
|
|
roles: string[];
|
|
}
|
|
export interface JwtResourceAccessEntry {
|
|
roles: string[];
|
|
}
|
|
export type JwtResourceAccess =
|
|
| Record<string, JwtResourceAccessEntry>
|
|
| undefined;
|
|
export interface JwtPayload {
|
|
sub: string;
|
|
email?: string;
|
|
preferred_username?: string;
|
|
given_name?: string;
|
|
family_name?: string;
|
|
scope?: string;
|
|
realm_access?: JwtRealmAccess;
|
|
resource_access?: JwtResourceAccess;
|
|
iat: number;
|
|
exp: number;
|
|
iss: string;
|
|
aud?: JwtAudience;
|
|
[claim: string]: unknown;
|
|
}
|
|
|
|
@Injectable()
|
|
export class KeycloakJwtStrategy extends PassportStrategy(Strategy, 'jwt') {
|
|
constructor() {
|
|
const baseUrl =
|
|
process.env.NODE_ENV === 'production'
|
|
? 'http://keycloak:8080'
|
|
: 'https://auth.clipperia.com.br';
|
|
|
|
super({
|
|
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
|
secretOrKeyProvider: jwksRsa.passportJwtSecret({
|
|
cache: true,
|
|
rateLimit: true,
|
|
jwksRequestsPerMinute: 5,
|
|
jwksUri: `${baseUrl}/realms/clipperia/protocol/openid-connect/certs`,
|
|
}),
|
|
algorithms: ['RS256'],
|
|
issuer: `${baseUrl}/realms/clipperia`,
|
|
ignoreExpiration: false,
|
|
});
|
|
}
|
|
|
|
validate(payload: JwtPayload): JwtPayload {
|
|
if (payload.exp < Date.now() / 1000) {
|
|
throw new UnauthorizedException('Token expirado');
|
|
}
|
|
|
|
return payload;
|
|
}
|
|
}
|