diff --git a/src/app.module.ts b/src/app.module.ts index 1f911ad..d271021 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -2,8 +2,10 @@ import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import configuration from './config/configuration'; import { AiModule } from './ai/ai.module'; +import { AuthModule } from './auth/auth.module'; import { PlatformModule } from './platform/platform.module'; import { ExotelModule } from './exotel/exotel.module'; +import { CallEventsModule } from './call-events/call-events.module'; @Module({ imports: [ @@ -12,8 +14,10 @@ import { ExotelModule } from './exotel/exotel.module'; isGlobal: true, }), AiModule, + AuthModule, PlatformModule, ExotelModule, + CallEventsModule, ], }) export class AppModule {} diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts new file mode 100644 index 0000000..4c74e16 --- /dev/null +++ b/src/auth/auth.controller.ts @@ -0,0 +1,85 @@ +import { Controller, Post, Body, Logger, HttpException } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import axios from 'axios'; + +@Controller('auth') +export class AuthController { + private readonly logger = new Logger(AuthController.name); + private readonly graphqlUrl: string; + + constructor(private config: ConfigService) { + this.graphqlUrl = config.get('platform.graphqlUrl')!; + } + + @Post('login') + async login(@Body() body: { email: string; password: string }) { + this.logger.log(`Login attempt for ${body.email}`); + + try { + const response = await axios.post(this.graphqlUrl, { + query: `mutation GetLoginToken($email: String!, $password: String!) { + getLoginTokenFromCredentials( + email: $email + password: $password + origin: "http://localhost:5173" + ) { + loginToken { token } + } + }`, + variables: { email: body.email, password: body.password }, + }, { + headers: { 'Content-Type': 'application/json' }, + }); + + if (response.data.errors) { + throw new HttpException( + response.data.errors[0]?.message ?? 'Login failed', + 401, + ); + } + + return response.data.data.getLoginTokenFromCredentials; + } catch (error) { + if (error instanceof HttpException) throw error; + this.logger.error(`Login proxy failed: ${error}`); + throw new HttpException('Authentication service unavailable', 503); + } + } + + @Post('tokens') + async getTokens(@Body() body: { loginToken: string }) { + this.logger.log('Exchanging login token for access token'); + + try { + const response = await axios.post(this.graphqlUrl, { + query: `mutation GetAuthTokens($loginToken: String!) { + getAuthTokensFromLoginToken( + loginToken: $loginToken + origin: "http://localhost:5173" + ) { + tokens { + accessOrWorkspaceAgnosticToken { token } + refreshToken { token } + } + } + }`, + variables: { loginToken: body.loginToken }, + }, { + headers: { 'Content-Type': 'application/json' }, + }); + + if (response.data.errors) { + throw new HttpException( + response.data.errors[0]?.message ?? 'Token exchange failed', + 401, + ); + } + + return response.data.data.getAuthTokensFromLoginToken; + } catch (error) { + if (error instanceof HttpException) throw error; + this.logger.error(`Token exchange proxy failed: ${error}`); + throw new HttpException('Authentication service unavailable', 503); + } + } +} diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts new file mode 100644 index 0000000..2d08216 --- /dev/null +++ b/src/auth/auth.module.ts @@ -0,0 +1,7 @@ +import { Module } from '@nestjs/common'; +import { AuthController } from './auth.controller'; + +@Module({ + controllers: [AuthController], +}) +export class AuthModule {}