mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage-server
synced 2026-04-11 18:08:16 +00:00
feat: add auth proxy controller for login and token exchange
Adds POST /auth/login and POST /auth/tokens endpoints that proxy GraphQL mutations to the fortytwo-eap-core platform, letting the frontend use only the sidecar URL for authentication. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,8 +2,10 @@ import { Module } from '@nestjs/common';
|
|||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import configuration from './config/configuration';
|
import configuration from './config/configuration';
|
||||||
import { AiModule } from './ai/ai.module';
|
import { AiModule } from './ai/ai.module';
|
||||||
|
import { AuthModule } from './auth/auth.module';
|
||||||
import { PlatformModule } from './platform/platform.module';
|
import { PlatformModule } from './platform/platform.module';
|
||||||
import { ExotelModule } from './exotel/exotel.module';
|
import { ExotelModule } from './exotel/exotel.module';
|
||||||
|
import { CallEventsModule } from './call-events/call-events.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -12,8 +14,10 @@ import { ExotelModule } from './exotel/exotel.module';
|
|||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
}),
|
}),
|
||||||
AiModule,
|
AiModule,
|
||||||
|
AuthModule,
|
||||||
PlatformModule,
|
PlatformModule,
|
||||||
ExotelModule,
|
ExotelModule,
|
||||||
|
CallEventsModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|||||||
85
src/auth/auth.controller.ts
Normal file
85
src/auth/auth.controller.ts
Normal file
@@ -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<string>('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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/auth/auth.module.ts
Normal file
7
src/auth/auth.module.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { AuthController } from './auth.controller';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
controllers: [AuthController],
|
||||||
|
})
|
||||||
|
export class AuthModule {}
|
||||||
Reference in New Issue
Block a user