eletrotupi / tcc/ api/src/controllers/auth.tsd5dbfbd54d2fb3166d9d8ccdd14000bdcfb0dfdb
3.6 KB | 132 lines Raw
1
import { Request, Response, NextFunction } from 'express';
2
import {
3
  authenticateUser,
4
  generateToken,
5
  initiatePasswordReset,
6
  resetPassword,
7
  findUserByEmail
8
} from '@app/models/user';
9
import {
10
  validateRequiredFields
11
} from '@app/utils/validators';
12
import { verifyToken } from '@app/lib/jwt';
13

14
export const AuthController = {
15
  login: async (req: Request, res: Response, next: NextFunction) => {
16
    try {
17
      const { email, password } = req.body;
18

19
      const requiredValidation = validateRequiredFields(req.body, [
20
        'email', 'password'
21
      ]);
22

23
      if (!requiredValidation.valid) {
24
        return res.status(400).json({
25
          error: 'Missing required fields',
26
          missing: requiredValidation.missing
27
        });
28
      }
29

30
      const user = await authenticateUser(email, password);
31
      const jwtToken = generateToken(user.id, user.email);
32

33
      res.json({
34
        token: jwtToken,
35
        user: {
36
          id: user.id,
37
          email: user.email,
38
          firstName: user.firstName,
39
          lastName: user.lastName
40
        }
41
      });
42
    } catch (err: any) {
43
      if (err.message === 'Invalid credentials') {
44
        return res.status(401).json({ error: 'Invalid credentials' });
45
      }
46
      next(err);
47
    }
48
  },
49

50
  forgotPassword: async (req: Request, res: Response, next: NextFunction) => {
51
    try {
52
      const { email } = req.body;
53

54
      const requiredValidation = validateRequiredFields(req.body, ['email']);
55

56
      if (!requiredValidation.valid) {
57
        return res.status(400).json({
58
          error: 'Email is required',
59
          missing: requiredValidation.missing
60
        });
61
      }
62

63
      const result = await initiatePasswordReset(email);
64

65
      // In production, don't send token in response
66
      // Instead, send email with reset link
67
      res.json({
68
        message: 'Password reset instructions sent to your email',
69
        ...(!process.env.NODE_ENV || process.env.NODE_ENV === 'development' ? { token: result.token } : {})
70
      });
71
    } catch (err) {
72
      next(err);
73
    }
74
  },
75

76
  resetPassword: async (req: Request, res: Response, next: NextFunction) => {
77
    try {
78
      const { token, password } = req.body;
79

80
      const requiredValidation = validateRequiredFields(req.body, [
81
        'token', 'password'
82
      ]);
83

84
      if (!requiredValidation.valid) {
85
        return res.status(400).json({
86
          error: 'Missing required fields',
87
          missing: requiredValidation.missing
88
        });
89
      }
90

91
      await resetPassword(token, password);
92

93
      res.json({ message: 'Password successfully reset' });
94
    } catch (err: any) {
95
      if (err.message.includes('token')) {
96
        return res.status(400).json({ error: err.message });
97
      }
98
      next(err);
99
    }
100
  },
101

102
  verify: async (req: Request, res: Response, next: NextFunction) => {
103
    try {
104
      const authHeader = req.headers.authorization;
105

106
      if (!authHeader || !authHeader.startsWith('Bearer ')) {
107
        return res.status(401).json({ error: 'No token provided' });
108
      }
109

110
      const token = authHeader.substring(7);
111
      const payload = verifyToken(token);
112
      const user = await findUserByEmail(payload.email);
113

114
      res.json({
115
        valid: true,
116
        userId: payload.userId,
117
        email: payload.email,
118
        user: {
119
          firstName: user?.firstName,
120
          email: user?.email,
121
          lastName: user?.lastName,
122
          updatedAt: user?.updatedAt
123
        }
124
      });
125
    } catch (err: any) {
126
      if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
127
        return res.status(401).json({ error: 'Invalid or expired token' });
128
      }
129
      next(err);
130
    }
131
  }
132
};