import { Injectable } from "@nestjs/common"; import { PassportStrategy } from "@nestjs/passport"; import { ExtractJwt, Strategy } from "passport-jwt"; import * as jwksRsa from "jwks-rsa"; import { Request } from "express"; @Injectable() export class KeycloakStrategy extends PassportStrategy(Strategy, "keycloak") { constructor() { super({ jwtFromRequest: ExtractJwt.fromExtractors([ (req: Request) => req?.cookies?.access_token || null, ExtractJwt.fromAuthHeaderAsBearerToken(), ]), // 🔑 Get signing key from Keycloak secretOrKeyProvider: jwksRsa.passportJwtSecret({ cache: true, rateLimit: true, jwksRequestsPerMinute: 5, jwksUri: "https://keycloak.petermaquiran.xyz/realms/tvone/protocol/openid-connect/certs", }), //audience: "tvone-web", // your Keycloak clientId issuer: "https://keycloak.petermaquiran.xyz/realms/tvone", algorithms: ["RS256"], }); } async validate(payload: any) { return { userId: payload.sub, email: payload.email, name: payload.name, // Google profile image is usually in 'picture' email_verified: payload.email_verified, picture: payload.picture, roles: payload.realm_access?.roles || [], // Keep raw for debugging other custom claims raw: payload, }; } }