4
4
from rest_framework import status
5
5
from django .http import HttpResponseRedirect , HttpResponse
6
6
from django .conf import settings
7
+ from drf_spectacular .utils import extend_schema , OpenApiParameter , OpenApiExample , OpenApiResponse
8
+ from drf_spectacular .types import OpenApiTypes
7
9
from todo .services .google_oauth_service import GoogleOAuthService
8
10
from todo .services .user_service import UserService
9
11
from todo .utils .google_jwt_utils import (
24
26
25
27
26
28
class GoogleLoginView (APIView ):
29
+ @extend_schema (
30
+ operation_id = "google_login" ,
31
+ summary = "Initiate Google OAuth login" ,
32
+ description = "Redirects to Google OAuth authorization URL or returns JSON response with auth URL" ,
33
+ tags = ["auth" ],
34
+ parameters = [
35
+ OpenApiParameter (
36
+ name = "redirectURL" ,
37
+ type = OpenApiTypes .STR ,
38
+ location = OpenApiParameter .QUERY ,
39
+ description = "URL to redirect after successful authentication" ,
40
+ required = False ,
41
+ ),
42
+ OpenApiParameter (
43
+ name = "format" ,
44
+ type = OpenApiTypes .STR ,
45
+ location = OpenApiParameter .QUERY ,
46
+ description = "Response format: 'json' for JSON response, otherwise redirects" ,
47
+ required = False ,
48
+ ),
49
+ ],
50
+ responses = {
51
+ 200 : OpenApiResponse (description = "Google OAuth URL generated successfully" ),
52
+ 302 : OpenApiResponse (description = "Redirect to Google OAuth URL" ),
53
+ },
54
+ )
27
55
def get (self , request : Request ):
28
56
redirect_url = request .query_params .get ("redirectURL" )
29
57
auth_url , state = GoogleOAuthService .get_authorization_url (redirect_url )
@@ -51,6 +79,40 @@ class GoogleCallbackView(APIView):
51
79
The frontend implementation will redirect to the frontend and process the callback via POST request.
52
80
"""
53
81
82
+ @extend_schema (
83
+ operation_id = "google_callback" ,
84
+ summary = "Handle Google OAuth callback" ,
85
+ description = "Processes the OAuth callback from Google and creates/updates user account" ,
86
+ tags = ["auth" ],
87
+ parameters = [
88
+ OpenApiParameter (
89
+ name = "code" ,
90
+ type = OpenApiTypes .STR ,
91
+ location = OpenApiParameter .QUERY ,
92
+ description = "Authorization code from Google" ,
93
+ required = True ,
94
+ ),
95
+ OpenApiParameter (
96
+ name = "state" ,
97
+ type = OpenApiTypes .STR ,
98
+ location = OpenApiParameter .QUERY ,
99
+ description = "State parameter for CSRF protection" ,
100
+ required = True ,
101
+ ),
102
+ OpenApiParameter (
103
+ name = "error" ,
104
+ type = OpenApiTypes .STR ,
105
+ location = OpenApiParameter .QUERY ,
106
+ description = "Error from Google OAuth" ,
107
+ required = False ,
108
+ ),
109
+ ],
110
+ responses = {
111
+ 200 : OpenApiResponse (description = "OAuth callback processed successfully" ),
112
+ 400 : OpenApiResponse (description = "Bad request - invalid parameters" ),
113
+ 500 : OpenApiResponse (description = "Internal server error" ),
114
+ },
115
+ )
54
116
def get (self , request : Request ):
55
117
if "error" in request .query_params :
56
118
error = request .query_params .get ("error" )
@@ -274,6 +336,17 @@ def _set_auth_cookies(self, response, tokens):
274
336
275
337
276
338
class GoogleAuthStatusView (APIView ):
339
+ @extend_schema (
340
+ operation_id = "google_auth_status" ,
341
+ summary = "Check authentication status" ,
342
+ description = "Check if the user is authenticated and return user information" ,
343
+ tags = ["auth" ],
344
+ responses = {
345
+ 200 : OpenApiResponse (description = "Authentication status retrieved successfully" ),
346
+ 401 : OpenApiResponse (description = "Unauthorized - invalid or missing token" ),
347
+ 500 : OpenApiResponse (description = "Internal server error" ),
348
+ },
349
+ )
277
350
def get (self , request : Request ):
278
351
access_token = request .COOKIES .get ("ext-access" )
279
352
@@ -304,6 +377,17 @@ def get(self, request: Request):
304
377
305
378
306
379
class GoogleRefreshView (APIView ):
380
+ @extend_schema (
381
+ operation_id = "google_refresh_token" ,
382
+ summary = "Refresh access token" ,
383
+ description = "Refresh the access token using the refresh token from cookies" ,
384
+ tags = ["auth" ],
385
+ responses = {
386
+ 200 : OpenApiResponse (description = "Token refreshed successfully" ),
387
+ 401 : OpenApiResponse (description = "Unauthorized - invalid or missing refresh token" ),
388
+ 500 : OpenApiResponse (description = "Internal server error" ),
389
+ },
390
+ )
307
391
def get (self , request : Request ):
308
392
refresh_token = request .COOKIES .get ("ext-refresh" )
309
393
@@ -344,9 +428,44 @@ def _get_cookie_config(self):
344
428
345
429
346
430
class GoogleLogoutView (APIView ):
431
+ @extend_schema (
432
+ operation_id = "google_logout" ,
433
+ summary = "Logout user" ,
434
+ description = "Logout the user by clearing authentication cookies" ,
435
+ tags = ["auth" ],
436
+ parameters = [
437
+ OpenApiParameter (
438
+ name = "redirectURL" ,
439
+ type = OpenApiTypes .STR ,
440
+ location = OpenApiParameter .QUERY ,
441
+ description = "URL to redirect after logout" ,
442
+ required = False ,
443
+ ),
444
+ OpenApiParameter (
445
+ name = "format" ,
446
+ type = OpenApiTypes .STR ,
447
+ location = OpenApiParameter .QUERY ,
448
+ description = "Response format: 'json' for JSON response, otherwise redirects" ,
449
+ required = False ,
450
+ ),
451
+ ],
452
+ responses = {
453
+ 200 : OpenApiResponse (description = "Logout successful" ),
454
+ 302 : OpenApiResponse (description = "Redirect to specified URL or home page" ),
455
+ },
456
+ )
347
457
def get (self , request : Request ):
348
458
return self ._handle_logout (request )
349
459
460
+ @extend_schema (
461
+ operation_id = "google_logout_post" ,
462
+ summary = "Logout user (POST)" ,
463
+ description = "Logout the user by clearing authentication cookies (POST method)" ,
464
+ tags = ["auth" ],
465
+ responses = {
466
+ 200 : OpenApiResponse (description = "Logout successful" ),
467
+ },
468
+ )
350
469
def post (self , request : Request ):
351
470
return self ._handle_logout (request )
352
471
@@ -371,10 +490,9 @@ def _handle_logout(self, request: Request):
371
490
redirect_url = redirect_url or "/"
372
491
response = HttpResponseRedirect (redirect_url )
373
492
374
- response .delete_cookie ("ext-access" , path = "/" )
375
- response .delete_cookie ("ext-refresh" , path = "/" )
376
- response .delete_cookie (settings .SESSION_COOKIE_NAME , path = "/" )
377
- request .session .flush ()
493
+ config = self ._get_cookie_config ()
494
+ response .delete_cookie ("ext-access" , ** config )
495
+ response .delete_cookie ("ext-refresh" , ** config )
378
496
379
497
return response
380
498
0 commit comments