import { Injectable } from '@angular/core'; export type CognitoAuthProvider = 'amplify' | 'oidc'; export interface CognitoAuthConfig { provider: CognitoAuthProvider; region: string; userPoolId: string; userPoolWebClientId: string; domain: string; redirectSignIn: string; redirectSignOut: string; scopes: string[]; requireAuth?: boolean; } interface AuthProviderApi { initialize(configuration: CognitoAuthConfig): Promise; signIn(): Promise; signOut(): Promise; isAuthenticated(): Promise; getIdToken(): Promise; getAccessToken(): Promise; handleCallback(): Promise; } @Injectable({ providedIn: 'root' }) export class CognitoAuthService implements AuthProviderApi { private configuration: CognitoAuthConfig | null = null; private activeProvider: CognitoAuthProvider | null = null; async initialize(configuration: CognitoAuthConfig): Promise { this.configuration = configuration; this.activeProvider = configuration.provider; if (configuration.provider === 'amplify') { const { Amplify } = await import('aws-amplify'); Amplify.configure({ Auth: { region: configuration.region, userPoolId: configuration.userPoolId, userPoolWebClientId: configuration.userPoolWebClientId, oauth: { domain: configuration.domain, scope: configuration.scopes, redirectSignIn: configuration.redirectSignIn, redirectSignOut: configuration.redirectSignOut, responseType: 'code' } } }); return; } if (configuration.provider === 'oidc') { // Configuration du provider OIDC via angular-oauth2-oidc. // On s'attend à ce que l'app configure OAuthService au bootstrap // (loadDiscoveryDocumentAndLogin, etc.). Ici, rien à faire si ce n'est valider la présence. const { OAuthService } = await import('angular-oauth2-oidc'); const injector = (window as any).ngInjector; if (!injector) { throw new Error('Injector Angular global introuvable. Exposez window.ngInjector au bootstrap.'); } const oauthService = injector.get(OAuthService); if (!oauthService) { throw new Error('OAuthService non disponible. Vérifiez l\'installation et la configuration angular-oauth2-oidc.'); } return; } throw new Error('Provider non pris en charge. Utilisez "amplify" ou "oidc".'); } async signIn(): Promise { this.assertInitialized(); if (this.activeProvider === 'amplify') { const { Auth } = await import('aws-amplify'); await Auth.federatedSignIn(); return; } if (this.activeProvider === 'oidc') { const { OAuthService } = await import('angular-oauth2-oidc'); const injector = (window as any).ngInjector; const oauthService = injector.get(OAuthService); oauthService.initLoginFlow(); return; } } async signOut(): Promise { this.assertInitialized(); if (this.activeProvider === 'amplify') { const { Auth } = await import('aws-amplify'); await Auth.signOut(); return; } if (this.activeProvider === 'oidc') { const { OAuthService } = await import('angular-oauth2-oidc'); const injector = (window as any).ngInjector; const oauthService = injector.get(OAuthService); oauthService.logOut(); return; } } async isAuthenticated(): Promise { this.assertInitialized(); if (this.activeProvider === 'amplify') { try { const { Auth } = await import('aws-amplify'); const session = await Auth.currentSession(); return !!session?.getIdToken()?.getJwtToken(); } catch { return false; } } if (this.activeProvider === 'oidc') { try { const { OAuthService } = await import('angular-oauth2-oidc'); const injector = (window as any).ngInjector; const oauthService = injector.get(OAuthService); return oauthService.hasValidAccessToken() || oauthService.hasValidIdToken(); } catch { return false; } } return false; } async getIdToken(): Promise { this.assertInitialized(); if (this.activeProvider === 'amplify') { try { const { Auth } = await import('aws-amplify'); const session = await Auth.currentSession(); return session.getIdToken().getJwtToken() ?? null; } catch { return null; } } if (this.activeProvider === 'oidc') { try { const { OAuthService } = await import('angular-oauth2-oidc'); const injector = (window as any).ngInjector; const oauthService = injector.get(OAuthService); return oauthService.getIdToken() ?? null; } catch { return null; } } return null; } async getAccessToken(): Promise { this.assertInitialized(); if (this.activeProvider === 'amplify') { try { const { Auth } = await import('aws-amplify'); const session = await Auth.currentSession(); return session.getAccessToken().getJwtToken() ?? null; } catch { return null; } } if (this.activeProvider === 'oidc') { try { const { OAuthService } = await import('angular-oauth2-oidc'); const injector = (window as any).ngInjector; const oauthService = injector.get(OAuthService); return oauthService.getAccessToken() ?? null; } catch { return null; } } return null; } async handleCallback(): Promise { this.assertInitialized(); if (this.activeProvider === 'amplify') { // Amplify gère l'échange code->tokens automatiquement lors du retour. // Appeler currentSession() force la résolution de la session. const { Auth } = await import('aws-amplify'); await Auth.currentSession(); return; } if (this.activeProvider === 'oidc') { // Pour angular-oauth2-oidc, la prise en charge est faite au bootstrap avec // loadDiscoveryDocumentAndLogin(). Rien à faire ici si c'est déjà configuré. return; } } async ensureAuthenticated(loginRoute: string): Promise { const isAuthed = await this.isAuthenticated(); if (isAuthed) { return true; } if (this.configuration?.requireAuth) { // Redirection douce vers la page de login Angular window.location.assign(loginRoute); return false; } return true; } private assertInitialized(): void { if (!this.configuration || !this.activeProvider) { throw new Error('CognitoAuthService non initialisé. Appelez initialize(config).'); } } }