A social knowledge tool for researchers built on ATProto
at main 1.8 kB view raw
1import { Controller } from '../../../../../shared/infrastructure/http/Controller'; 2import { Request, Response } from 'express'; 3import { CompleteOAuthSignInUseCase } from '../../../application/use-cases/CompleteOAuthSignInUseCase'; 4import { CookieService } from '../../../../../shared/infrastructure/http/services/CookieService'; 5import { configService } from 'src/shared/infrastructure/config'; 6 7export class CompleteOAuthSignInController extends Controller { 8 constructor( 9 private completeOAuthSignInUseCase: CompleteOAuthSignInUseCase, 10 private cookieService: CookieService, 11 ) { 12 super(); 13 } 14 15 async executeImpl(req: Request, res: Response): Promise<any> { 16 const appUrl = configService.getAppConfig().appUrl; 17 try { 18 const { code, state, iss } = req.query; 19 20 if (!code || !state || !iss) { 21 return this.badRequest(res, 'Missing required parameters'); 22 } 23 24 const result = await this.completeOAuthSignInUseCase.execute({ 25 code: code as string, 26 state: state as string, 27 iss: iss as string, 28 }); 29 30 if (result.isErr()) { 31 // Instead of returning JSON, redirect with error 32 return res.redirect( 33 `${appUrl}/login?error=${encodeURIComponent(result.error.message)}`, 34 ); 35 } 36 37 // Set tokens in httpOnly cookies 38 this.cookieService.setTokens(res, { 39 accessToken: result.value.accessToken, 40 refreshToken: result.value.refreshToken, 41 }); 42 43 // Redirect back to frontend without tokens in URL (more secure) 44 return res.redirect(`${appUrl}/auth/complete`); 45 } catch (error: any) { 46 return res.redirect( 47 `${appUrl}/login?error=${encodeURIComponent(error.message || 'Unknown error')}`, 48 ); 49 } 50 } 51}