1import { Inject, Body, Controller, Get, HttpCode, Post, Query, Req, Res } from "@nestjs/common";
2import type { Request, Response } from "express";
3import { AuthService } from "./auth.service.js";
4import { TwoFactorService } from "../org/two-factor.service.js";
5import { ZodValidate } from "../../common/pipes/zod-validation.pipe.js";
6import {
7 type LoginInput,
8 type LogoutInput,
9 type RefreshInput,
10 type RegisterInput,
11 type ResetPasswordConfirmInput,
12 type ResetPasswordInput,
13 LoginDto,
14 LogoutDto,
15 RefreshDto,
16 RegisterDto,
17 ResetPasswordConfirmDto,
18 ResetPasswordDto,
19 TwoFactorVerifyDto,
20 type TwoFactorVerifyInput
21} from "./dto.js";
22
23@Controller("auth")
24export class AuthController {
25 constructor(
26 @Inject(AuthService) private readonly auth: AuthService,
27 @Inject(TwoFactorService) private readonly twoFactor: TwoFactorService
28 ) {}
29
30 @Post("register")
31 register(
32 @Body(ZodValidate(RegisterDto)) body: RegisterInput,
33 @Req() req: Request,
34 @Res({ passthrough: true }) res: Response
35 ) {
36 return this.auth.register(body, { req, res });
37 }
38
39
40
41
42
43 @HttpCode(200)
44 @Post("login")
45 login(
46 @Body(ZodValidate(LoginDto)) body: LoginInput,
47 @Req() req: Request,
48 @Res({ passthrough: true }) res: Response
49 ) {
50 return this.auth.login(body, { req, res });
51 }
52
53 @HttpCode(200)
54 @Post("refresh")
55 refresh(
56 @Body(ZodValidate(RefreshDto)) body: RefreshInput,
57 @Req() req: Request,
58 @Res({ passthrough: true }) res: Response
59 ) {
60 return this.auth.refresh(body.refreshToken ?? this.auth.readRefreshCookie(req), { req, res });
61 }
62
63
64
65
66 @HttpCode(200)
67 @Post("2fa/verify")
68 verify2fa(
69 @Body(ZodValidate(TwoFactorVerifyDto)) body: TwoFactorVerifyInput,
70 @Req() req: Request,
71 @Res({ passthrough: true }) res: Response
72 ) {
73 return this.auth.complete2Fa(body, { req, res });
74 }
75
76
77
78
79 @Get("2fa/status")
80 async twoFactorStatus(@Req() req: Request) {
81 return { enrolled: await this.twoFactor.isEnrolled(req.auth!.userId!) };
82 }
83
84 @Post("2fa/enroll")
85 twoFactorEnroll(@Req() req: Request) {
86 return this.twoFactor.enroll(req.auth!.userId!, req);
87 }
88
89 @Post("2fa/disable")
90 async twoFactorDisable(@Req() req: Request) {
91 await this.twoFactor.disable(req.auth!.userId!, req);
92 return { enrolled: false };
93 }
94
95 @Post("logout")
96 async logout(
97 @Body(ZodValidate(LogoutDto)) body: LogoutInput,
98 @Req() req: Request,
99 @Res({ passthrough: true }) res: Response
100 ) {
101 await this.auth.logout(this.auth.readRefreshCookie(req), body.sessionId, { req, res });
102 return { loggedOut: true };
103 }
104
105 @Get("me")
106 me(@Req() req: Request) {
107 return this.auth.me(req.auth!.userId!);
108 }
109
110
117 @Get("sso/options")
118 ssoOptions(@Query("email") email: string | undefined) {
119 return this.auth.ssoOptions(email ?? "");
120 }
121
122
123 @Post("reset-password")
124 resetPassword(@Body(ZodValidate(ResetPasswordDto)) body: ResetPasswordInput) {
125 return this.auth.resetPassword(body.email).then(() => ({ sent: true }));
126 }
127
128 @Post("reset-password/confirm")
129 confirmReset(
130 @Body(ZodValidate(ResetPasswordConfirmDto)) body: ResetPasswordConfirmInput,
131 @Req() req: Request
132 ) {
133 return this.auth.resetPasswordConfirm(body, { req });
134 }
135}
136