return profile picture

This commit is contained in:
2026-04-17 14:53:21 +01:00
parent 36b2eee680
commit c4eb6ef53a
8 changed files with 58 additions and 3 deletions
+11
View File
@@ -0,0 +1,11 @@
// auth.module.ts
import { Module } from "@nestjs/common";
import { PassportModule } from "@nestjs/passport";
import { KeycloakStrategy } from "./keycloak.strategy";
@Module({
imports: [PassportModule],
providers: [KeycloakStrategy], // 👈 THIS IS THE FIX
exports: [PassportModule],
})
export class AuthModule {}
+5
View File
@@ -0,0 +1,5 @@
import { Injectable } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";
@Injectable()
export class KeycloakAuthGuard extends AuthGuard("keycloak") {}
+41
View File
@@ -0,0 +1,41 @@
import { Injectable } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { ExtractJwt, Strategy } from "passport-jwt";
import * as jwksRsa from "jwks-rsa";
@Injectable()
export class KeycloakStrategy extends PassportStrategy(Strategy, "keycloak") {
constructor() {
super({
jwtFromRequest: 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) {
console.log('Full JWT Payload:', payload);
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 || `https://profiles.google.com/s2/photos/profile/${payload.email}`,
roles: payload.realm_access?.roles || [],
// Keep raw for debugging other custom claims
raw: payload,
};
}
}
+24
View File
@@ -0,0 +1,24 @@
import { KeycloakAuthGuard } from '../auth/keycloak.guard';
import { ProfileService } from './profile.service';
import { Controller, Get, UseGuards, Request } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Controller('profile')
export class ProfileController {
constructor(private readonly profileService: ProfileService) {}
@UseGuards(AuthGuard('keycloak'))
@Get()
getProfile(@Request() req) {
// The 'user' object here is exactly what you returned from validate()
return {
email: req.user.email,
name: req.user.name,
picture: req.user.picture,
email_verified: req.user.email_verified,
roles: req.user.roles,
};
}
}
+16
View File
@@ -0,0 +1,16 @@
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { ProfileController } from './profile.controller';
import { ProfileService } from './profile.service';
import { KeycloakStrategy } from '../auth/keycloak.strategy';
@Module({
imports: [
// Registers the 'keycloak' strategy as a default if needed
PassportModule.register({ defaultStrategy: 'keycloak' }),
],
controllers: [ProfileController],
providers: [ProfileService, KeycloakStrategy],
exports: [],
})
export class ProfileModule {}
+8
View File
@@ -0,0 +1,8 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class ProfileService {
getProfile(): string {
return 'Hello World!';
}
}