11import type {
2- GoogleAuthSchema ,
2+ GoogleCodeSchema ,
33 RefreshTokenSchema ,
44 SigninSchema ,
55 SignupSchema
66} from '@/schemas'
7- import type { GoogleUserResponse , JwtPayload , TypedRequestBody } from '@/types'
7+ import type { JwtPayload } from '@/types'
88import type { NextFunction , Request , Response } from 'express'
9+ import type {
10+ TypedRequestBody ,
11+ TypedRequestQuery
12+ } from 'zod-express-middleware'
913
1014import { prisma } from '@/prisma'
1115import { hash , verify } from 'argon2'
@@ -24,10 +28,17 @@ const {
2428 ACCESS_JWT_ALGORITHM ,
2529 REFRESH_JWT_ALGORITHM ,
2630 GOOGLE_CLIENT_ID ,
27- GOOGLE_CLIENT_SECRET
31+ GOOGLE_CLIENT_SECRET ,
32+ GOOGLE_REDIRECT_URI
2833} = env
2934
3035class AuthController {
36+ googleClient = new OAuth2Client (
37+ GOOGLE_CLIENT_ID ,
38+ GOOGLE_CLIENT_SECRET ,
39+ GOOGLE_REDIRECT_URI
40+ )
41+
3142 signup = async (
3243 { body } : TypedRequestBody < typeof SignupSchema > ,
3344 res : Response ,
@@ -84,23 +95,40 @@ class AuthController {
8495 res . json ( { user : userWithoutPassword , ...tokens } )
8596 }
8697
87- google = async (
88- { body } : TypedRequestBody < typeof GoogleAuthSchema > ,
89- res : Response
98+ googleRedirect = async ( _ : Request , res : Response ) => {
99+ const url = this . googleClient . generateAuthUrl ( {
100+ access_type : 'offline' ,
101+ scope : [ 'profile' , 'email' ]
102+ } )
103+
104+ res . redirect ( url )
105+ }
106+
107+ googleCallback = async (
108+ req : TypedRequestQuery < typeof GoogleCodeSchema > ,
109+ res : Response ,
110+ next : NextFunction
90111 ) => {
91- const oAuth2Client = new OAuth2Client (
92- GOOGLE_CLIENT_ID ,
93- GOOGLE_CLIENT_SECRET ,
94- 'postmessage'
95- )
112+ const { tokens } = await this . googleClient . getToken ( req . query . code )
96113
97- const { tokens } = await oAuth2Client . getToken ( body . code )
114+ if ( ! tokens . id_token ) return next ( Forbidden ( ) )
98115
99- const { name, email, picture } = await this . getUserInfoFromGoogleApi (
100- tokens . access_token !
101- )
116+ const ticket = await this . googleClient . verifyIdToken ( {
117+ idToken : tokens . id_token ,
118+ audience : GOOGLE_CLIENT_ID
119+ } )
102120
103- const user = await prisma . user . findUnique ( { where : { email } } )
121+ const payload = ticket . getPayload ( )
122+
123+ if ( ! payload || ! payload . email || ! payload . name || ! payload . picture ) {
124+ return next ( Forbidden ( 'Invalid token' ) )
125+ }
126+
127+ const { name, email, picture } = payload
128+
129+ const user = await prisma . user . findUnique ( {
130+ where : { email }
131+ } )
104132
105133 if ( ! user ) {
106134 const user = await prisma . user . create ( {
@@ -131,7 +159,7 @@ class AuthController {
131159 }
132160 }
133161
134- tokens = async (
162+ refresh = async (
135163 { body } : TypedRequestBody < typeof RefreshTokenSchema > ,
136164 res : Response ,
137165 next : NextFunction
@@ -186,18 +214,6 @@ class AuthController {
186214
187215 return { accessToken, refreshToken }
188216 }
189-
190- private getUserInfoFromGoogleApi = async ( accessToken : string ) => {
191- const URL = 'https://www.googleapis.com/oauth2/v3/userinfo'
192-
193- const r = await fetch ( URL , {
194- headers : { Authorization : `Bearer ${ accessToken } ` }
195- } )
196-
197- const userInfo = ( await r . json ( ) ) as GoogleUserResponse
198-
199- return userInfo
200- }
201217}
202218
203219export const authController = new AuthController ( )
0 commit comments