1
+ const User = require ( '../models/User' )
2
+ const bcrypt = require ( 'bcrypt' )
3
+ const jwt = require ( 'jsonwebtoken' )
4
+
5
+ // @desc Login
6
+ // @route POST /auth
7
+ // @access Public
8
+ const login = async ( req , res ) => {
9
+ const { username, password } = req . body
10
+
11
+ if ( ! username || ! password ) {
12
+ return res . status ( 400 ) . json ( { message : 'All fields are required' } )
13
+ }
14
+
15
+ const foundUser = await User . findOne ( { username } ) . exec ( )
16
+
17
+ if ( ! foundUser || ! foundUser . active ) {
18
+ return res . status ( 401 ) . json ( { message : 'Unauthorized' } )
19
+ }
20
+
21
+ const match = await bcrypt . compare ( password , foundUser . password )
22
+
23
+ if ( ! match ) return res . status ( 401 ) . json ( { message : 'Unauthorized' } )
24
+
25
+ const accessToken = jwt . sign (
26
+ {
27
+ "UserInfo" : {
28
+ "username" : foundUser . username ,
29
+ "roles" : foundUser . roles
30
+ }
31
+ } ,
32
+ process . env . ACCESS_TOKEN_SECRET ,
33
+ { expiresIn : '15m' }
34
+ )
35
+
36
+ const refreshToken = jwt . sign (
37
+ { "username" : foundUser . username } ,
38
+ process . env . REFRESH_TOKEN_SECRET ,
39
+ { expiresIn : '7d' }
40
+ )
41
+
42
+ // Create secure cookie with refresh token
43
+ res . cookie ( 'jwt' , refreshToken , {
44
+ httpOnly : true , //accessible only by web server
45
+ secure : true , //https
46
+ sameSite : 'None' , //cross-site cookie
47
+ maxAge : 7 * 24 * 60 * 60 * 1000 //cookie expiry: set to match rT
48
+ } )
49
+
50
+ // Send accessToken containing username and roles
51
+ res . json ( { accessToken } )
52
+ }
53
+
54
+ // @desc Refresh
55
+ // @route GET /auth/refresh
56
+ // @access Public - because access token has expired
57
+ const refresh = ( req , res ) => {
58
+ const cookies = req . cookies
59
+
60
+ if ( ! cookies ?. jwt ) return res . status ( 401 ) . json ( { message : 'Unauthorized' } )
61
+
62
+ const refreshToken = cookies . jwt
63
+
64
+ jwt . verify (
65
+ refreshToken ,
66
+ process . env . REFRESH_TOKEN_SECRET ,
67
+ async ( err , decoded ) => {
68
+ if ( err ) return res . status ( 403 ) . json ( { message : 'Forbidden' } )
69
+
70
+ const foundUser = await User . findOne ( { username : decoded . username } ) . exec ( )
71
+
72
+ if ( ! foundUser ) return res . status ( 401 ) . json ( { message : 'Unauthorized' } )
73
+
74
+ const accessToken = jwt . sign (
75
+ {
76
+ "UserInfo" : {
77
+ "username" : foundUser . username ,
78
+ "roles" : foundUser . roles
79
+ }
80
+ } ,
81
+ process . env . ACCESS_TOKEN_SECRET ,
82
+ { expiresIn : '15m' }
83
+ )
84
+
85
+ res . json ( { accessToken } )
86
+ }
87
+ )
88
+ }
89
+
90
+ // @desc Logout
91
+ // @route POST /auth/logout
92
+ // @access Public - just to clear cookie if exists
93
+ const logout = ( req , res ) => {
94
+ const cookies = req . cookies
95
+ if ( ! cookies ?. jwt ) return res . sendStatus ( 204 ) //No content
96
+ res . clearCookie ( 'jwt' , { httpOnly : true , sameSite : 'None' , secure : true } )
97
+ res . json ( { message : 'Cookie cleared' } )
98
+ }
99
+
100
+ module . exports = {
101
+ login,
102
+ refresh,
103
+ logout
104
+ }
0 commit comments