import {Controller} from '../../../http/Controller' import {Inject, Injectable} from '../../../di' import {Config} from '../../../service/Config' import {Request} from '../../../http/lifecycle/Request' import {ResponseObject, Route} from '../../../http/routing/Route' import {ErrorWithContext} from '../../../util' import {OAuth2Repository} from './OAuth2Repository' import {json} from '../../../http/response/JSONResponseFactory' export interface OAuth2LoginConfig { name: string, clientId: string, clientSecret: string, redirectUrl: string, authorizationCodeField: string, tokenEndpoint: string, tokenEndpointMapping?: { clientId?: string, clientSecret?: string, grantType?: string, codeKey?: string, }, tokenEndpointResponseMapping?: { token?: string, expiresIn?: string, expiresAt?: string, }, userEndpoint: string, userEndpointResponseMapping?: { identifier?: string, display?: string, }, } export function isOAuth2LoginConfig(what: unknown): what is OAuth2LoginConfig { return ( Boolean(what) && typeof (what as any).name === 'string' && typeof (what as any).clientId === 'string' && typeof (what as any).clientSecret === 'string' && typeof (what as any).redirectUrl === 'string' && typeof (what as any).authorizationCodeField === 'string' && typeof (what as any).tokenEndpoint === 'string' && typeof (what as any).userEndpoint === 'string' ) } @Injectable() export class OAuth2LoginController extends Controller { public static routes(configName: string): void { Route.group(`/auth/${configName}`, () => { Route.get('login', (request: Request) => { const controller = request.make(OAuth2LoginController, configName) return controller.getLogin() }).pre('@auth:guest') }).pre('@auth:web') } @Inject() protected readonly config!: Config constructor( protected readonly request: Request, protected readonly configName: string, ) { super(request) } public async getLogin(): Promise { const repo = this.getRepository() if ( repo.shouldRedirect() ) { return repo.redirect() } // We were redirected from the auth source const user = await repo.redeem() return json(user) } protected getRepository(): OAuth2Repository { return this.request.make(OAuth2Repository, this.getConfig()) } protected getConfig(): OAuth2LoginConfig { const config = this.config.get(`auth.sources.${this.configName}`) if ( !isOAuth2LoginConfig(config) ) { throw new ErrorWithContext('Invalid OAuth2 source config.', { configName: this.configName, config, }) } return config } }