All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 31s
Backend: cookie-parser, auth guard token introspection (SuperOAuth profile API),
fix réponse wrappée { success, data: { user, linkedProviders } }.
Frontend: page login 4 providers PKCE, callback SSR-safe (browser guard),
search améliorée (debounce, pagination, toast, feedback visuel ajout),
list complète (7 tabs, progression inline, score, vue grille/liste, cards goldées),
profil (XP bar, grades, 8 stats), user store partagé, toast system.
61 lines
1.6 KiB
TypeScript
61 lines
1.6 KiB
TypeScript
import {
|
|
CanActivate,
|
|
ExecutionContext,
|
|
Injectable,
|
|
UnauthorizedException,
|
|
} from '@nestjs/common';
|
|
import { ConfigService } from '@nestjs/config';
|
|
|
|
@Injectable()
|
|
export class AuthGuard implements CanActivate {
|
|
constructor(private readonly configService: ConfigService) {}
|
|
|
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
const request = context.switchToHttp().getRequest();
|
|
const token = this.extractToken(request);
|
|
|
|
if (!token) {
|
|
throw new UnauthorizedException('No token provided');
|
|
}
|
|
|
|
const userInfo = await this.introspect(token);
|
|
if (!userInfo) {
|
|
throw new UnauthorizedException('Invalid token');
|
|
}
|
|
|
|
request.user = userInfo;
|
|
return true;
|
|
}
|
|
|
|
private extractToken(request: any): string | null {
|
|
const authHeader = request.headers.authorization;
|
|
if (authHeader?.startsWith('Bearer ')) {
|
|
return authHeader.slice(7);
|
|
}
|
|
return request.cookies?.access_token || null;
|
|
}
|
|
|
|
private async introspect(token: string): Promise<any> {
|
|
const url = this.configService.get('SUPEROAUTH_URL');
|
|
try {
|
|
const res = await fetch(`${url}/api/v1/user/profile`, {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
if (!res.ok) return null;
|
|
const body = await res.json();
|
|
if (!body?.success || !body?.data?.user) return null;
|
|
|
|
const user = body.data.user;
|
|
const avatar = body.data.linkedProviders?.[0]?.avatar || null;
|
|
|
|
return {
|
|
id: user.id,
|
|
nickname: user.nickname || user.email,
|
|
avatar,
|
|
};
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
}
|