import * as express from 'express' ; import { inject } from 'inversify' ; import { controller , interfaces , httpPost , httpGet } from 'inversify-express-utils' ; import { ApiEndpoints , CookieNames , TokenExpirationTimes , Environments } from '@centsideas/enums' ; import { RpcClient , RPC_CLIENT_FACTORY , RpcClientFactory } from '@centsideas/rpc' ; import { AuthenticationCommands , AuthenticationCommandsService } from '@centsideas/schemas' ; import { GlobalConfig } from '@centsideas/config' ; import { GatewayConfig } from './gateway.config' ; @ controller ( `/${ ApiEndpoints . Authentication }` ) export class AuthenticationController implements interfaces . Controller { private readonly isProd = this . globalConfig . get ( 'global.environment' ) === Environments . Prod ; private authenticationRpc : RpcClient < AuthenticationCommands . Service > = this . rpcFactory ( { host : this . config . get ( 'authentication.rpc.host' ) , port : this . config . getNumber ( 'authentication.rpc.port' ) , service : AuthenticationCommandsService , } ) ; constructor ( private config , private globalConfig , @ inject ( RPC_CLIENT_FACTORY ) private rpcFactory ) { } @ httpPost ( '/signin/email' ) requestEmailSignIn ( req ) { const { email } = req . body ; return this . authenticationRpc . client . requestEmailSignIn ( { email } ) ; } @ httpPost ( '/signin/email/confirm' ) async confirmEmailSignIn ( req , res ) { const { token } = req . body ; const data = await this . authenticationRpc . client . confirmEmailSignIn ( { signInToken : token } ) ; const { refreshToken , accessToken , userId } = data ; res . cookie ( CookieNames . RefreshToken , refreshToken , this . refreshTokenCookieOptions ) ; return { accessToken , userId } ; } @ httpGet ( '/signin/google/url' ) async getGoogleSignInUrl ( ) { return this . authenticationRpc . client . googleSignInUrl ( ) ; } @ httpPost ( '/signin/google' ) async googleSignIn ( req , res ) { const { code } = req . body ; const data = await this . authenticationRpc . client . googleSignIn ( { code } ) ; const { refreshToken , accessToken , userId } = data ; res . cookie ( CookieNames . RefreshToken , refreshToken , this . refreshTokenCookieOptions ) ; return { accessToken , userId } ; } @ httpPost ( '/refresh' ) async refreshToken ( req , res ) { try { const current = req . cookies [ CookieNames . RefreshToken ] ; const data = await this . authenticationRpc . client . refreshToken ( { refreshToken : current } ) ; const { accessToken , refreshToken , userId } = data ; res . cookie ( CookieNames . RefreshToken , refreshToken , this . refreshTokenCookieOptions ) ; return { accessToken , userId } ; } catch ( error ) { res . cookie ( CookieNames . RefreshToken , '' , { maxAge : 0 } ) . status ( 401 ) ; throw error ; } } @ httpPost ( '/signout' ) async signOut ( req , res ) { const refreshToken = req . cookies [ CookieNames . RefreshToken ] ; await this . authenticationRpc . client . signOut ( { refreshToken } ) ; res . cookie ( CookieNames . RefreshToken , '' , { maxAge : 0 } ) ; } @ httpPost ( '/revoke' ) revokeRefreshToken ( req ) { const { sessionId } = req . body ; return this . authenticationRpc . client . revokeRefreshToken ( { sessionId } ) ; } @ httpGet ( '/google/signin/token' ) googleSignInToken ( req ) { return req . query . code ; } private get refreshTokenCookieOptions ( ) : express . CookieOptions { return { httpOnly : true , maxAge : TokenExpirationTimes . Refresh * 1000 , sameSite : this . isProd ? 'strict' : 'lax' , secure : this . isProd ? true : false , } ; } }