import { ValidatorOptions } from 'class-validator' ; import { TokenSet } from 'openid-client' ; import { Injectable } from '@nestjs/common' ; import { validateDto } from '@fc/common' ; import { LoggerService } from '@fc/logger' ; import { IOidcIdentity } from '@fc/oidc' ; import { IEventContext , TrackingService } from '@fc/tracking' ; import { MinIdentityDto , TokenResultDto } from '../dto' ; import { OidcClientTokenEvent , OidcClientUserinfoEvent } from '../events' ; import { OidcClientUserinfosFailedException } from '../exceptions' ; import { ExtraTokenParams , TokenParams , TokenResults , UserInfosParams , } from '../interfaces' ; import { OidcClientUtilsService } from './oidc-client-utils.service' ; const DTO_OPTIONS = { whitelist : true , forbidNonWhitelisted : true , } ; @ Injectable ( ) export class OidcClientService { constructor ( private readonly logger , private readonly tracking , public readonly utils ) { this . logger . setContext ( this . constructor . name ) ; } async getTokenFromProvider ( idpId , params , context , extraParams ? ) { todo const tokenSet = await this . utils . getTokenSet ( context , idpId , params , extraParams ) ; this . tracking . track ( OidcClientTokenEvent , context ) ; const { access_token : accessToken , id_token : idToken } = tokenSet ; const { acr , amr } = tokenSet . claims ( ) ; const tokenResult = { acr , amr , accessToken , idToken , } ; const errorsOutputs = await validateDto ( tokenResult , TokenResultDto , DTO_OPTIONS ) ; if ( errorsOutputs . length ) { throw new Error ( `"${ JSON . stringify ( tokenResult ) }" input was wrong from the result at DTO validation: ${ JSON . stringify ( errorsOutputs ) }` ) ; } this . logger . trace ( { search : { context , idpId , params , acr , amr , accessToken , tokenResult , idToken , } , } ) ; return tokenResult ; } async getUserInfosFromProvider ( { accessToken , idpId } , context ) { let identity ; try { identity = await this . utils . getUserInfo ( accessToken , idpId ) ; } catch ( error ) { this . logger . error ( error , 'getUserInfo' ) ; todo see https see https throw new OidcClientUserinfosFailedException ( ) ; } this . logger . trace ( { search : { context , idpId , accessToken , identity , } , } ) ; this . tracking . track ( OidcClientUserinfoEvent , context ) ; const errors = await validateDto ( identity , MinIdentityDto , { whitelist : true , } , { excludeExtraneousValues : true , } ) ; if ( errors . length ) { throw new Error ( `"${ idpId }" doesn't provide a minimum identity information: ${ JSON . stringify ( errors ) }` ) ; } return identity ; } async getEndSessionUrlFromProvider ( ipdId , stateFromSession , idTokenHint ? , postLogoutRedirectUri ? ) { return this . utils . getEndSessionUrl ( ipdId , stateFromSession , idTokenHint , postLogoutRedirectUri ) ; } }