3
3
from django .http import JsonResponse
4
4
5
5
from todo .utils .jwt_utils import verify_jwt_token
6
- from todo .utils .google_jwt_utils import validate_google_access_token
6
+ from todo .utils .google_jwt_utils import (
7
+ validate_google_access_token ,
8
+ validate_google_refresh_token ,
9
+ generate_google_access_token ,
10
+ )
7
11
from todo .exceptions .auth_exceptions import TokenMissingError , TokenExpiredError , TokenInvalidError
8
- from todo .exceptions .google_auth_exceptions import GoogleTokenExpiredError , GoogleTokenInvalidError
12
+ from todo .exceptions .google_auth_exceptions import (
13
+ GoogleTokenExpiredError ,
14
+ GoogleTokenInvalidError ,
15
+ GoogleRefreshTokenExpiredError ,
16
+ )
9
17
from todo .constants .messages import AuthErrorMessages , ApiErrors
10
18
from todo .dto .responses .error_response import ApiErrorResponse , ApiErrorDetail
11
19
@@ -25,7 +33,8 @@ def __call__(self, request):
25
33
auth_success = self ._try_authentication (request )
26
34
27
35
if auth_success :
28
- return self .get_response (request )
36
+ response = self .get_response (request )
37
+ return self ._process_response (request , response )
29
38
else :
30
39
error_response = ApiErrorResponse (
31
40
statusCode = status .HTTP_401_UNAUTHORIZED ,
@@ -73,25 +82,61 @@ def _try_google_auth(self, request) -> bool:
73
82
try :
74
83
google_token = request .COOKIES .get ("ext-access" )
75
84
76
- if not google_token :
85
+ if google_token :
86
+ try :
87
+ payload = validate_google_access_token (google_token )
88
+ self ._set_google_user_data (request , payload )
89
+ return True
90
+ except (GoogleTokenExpiredError , GoogleTokenInvalidError ):
91
+ pass
92
+
93
+ return self ._try_google_refresh (request )
94
+
95
+ except (GoogleTokenExpiredError , GoogleTokenInvalidError ) as e :
96
+ raise e
97
+ except Exception :
98
+ return False
99
+
100
+ def _try_google_refresh (self , request ) -> bool :
101
+ """Try to refresh Google access token"""
102
+ try :
103
+ refresh_token = request .COOKIES .get ("ext-refresh" )
104
+
105
+ if not refresh_token :
77
106
return False
78
107
79
- payload = validate_google_access_token ( google_token )
108
+ payload = validate_google_refresh_token ( refresh_token )
80
109
81
- request .auth_type = "google"
82
- request .user_id = payload ["user_id" ]
83
- request .google_id = payload ["google_id" ]
84
- request .user_email = payload ["email" ]
85
- request .user_name = payload ["name" ]
86
- request .user_role = "external_user"
110
+ user_data = {
111
+ "user_id" : payload ["user_id" ],
112
+ "google_id" : payload ["google_id" ],
113
+ "email" : payload ["email" ],
114
+ "name" : payload .get ("name" , "" ),
115
+ }
116
+
117
+ new_access_token = generate_google_access_token (user_data )
118
+
119
+ self ._set_google_user_data (request , payload )
120
+
121
+ request ._new_access_token = new_access_token
122
+ request ._access_token_expires = settings .GOOGLE_JWT ["ACCESS_TOKEN_LIFETIME" ]
87
123
88
124
return True
89
125
90
- except (GoogleTokenExpiredError , GoogleTokenInvalidError ) as e :
91
- raise e
126
+ except (GoogleRefreshTokenExpiredError , GoogleTokenInvalidError ):
127
+ return False
92
128
except Exception :
93
129
return False
94
130
131
+ def _set_google_user_data (self , request , payload ):
132
+ """Set Google user data on request"""
133
+ request .auth_type = "google"
134
+ request .user_id = payload ["user_id" ]
135
+ request .google_id = payload ["google_id" ]
136
+ request .user_email = payload ["email" ]
137
+ request .user_name = payload .get ("name" , "" )
138
+ request .user_role = "external_user"
139
+
95
140
def _try_rds_auth (self , request ) -> bool :
96
141
try :
97
142
rds_token = request .COOKIES .get (self .rds_cookie_name )
@@ -112,6 +157,25 @@ def _try_rds_auth(self, request) -> bool:
112
157
except Exception :
113
158
return False
114
159
160
+ def _process_response (self , request , response ):
161
+ """Process response and set new cookies if Google token was refreshed"""
162
+ if hasattr (request , "_new_access_token" ):
163
+ config = self ._get_cookie_config ()
164
+ response .set_cookie (
165
+ "ext-access" , request ._new_access_token , max_age = request ._access_token_expires , ** config
166
+ )
167
+ return response
168
+
169
+ def _get_cookie_config (self ):
170
+ """Get Google cookie configuration"""
171
+ return {
172
+ "path" : "/" ,
173
+ "domain" : settings .GOOGLE_COOKIE_SETTINGS .get ("COOKIE_DOMAIN" ),
174
+ "secure" : settings .GOOGLE_COOKIE_SETTINGS .get ("COOKIE_SECURE" , False ),
175
+ "httponly" : True ,
176
+ "samesite" : settings .GOOGLE_COOKIE_SETTINGS .get ("COOKIE_SAMESITE" , "Lax" ),
177
+ }
178
+
115
179
def _is_public_path (self , path : str ) -> bool :
116
180
return any (path .startswith (public_path ) for public_path in settings .PUBLIC_PATHS )
117
181
0 commit comments