validops-east-1 commited on
Commit
f3ab5f0
·
1 Parent(s): efa9f90

feat: warning

Browse files
app/api/v1/google_oauth.py CHANGED
@@ -55,6 +55,42 @@ def _http_error(exc: GoogleOAuthError) -> HTTPException:
55
  return HTTPException(status_code=exc.status_code, detail=exc.message)
56
 
57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  @router.post("/auth-url", response_model=GoogleOAuthAuthUrlResponse,
59
  summary="Generate a Google OAuth authorization URL (Step 1)")
60
  async def create_auth_url(
@@ -78,7 +114,14 @@ async def create_auth_url(
78
  body.client_id[:8],
79
  (time.perf_counter() - start) * 1000,
80
  )
81
- return GoogleOAuthAuthUrlResponse(success=True, auth_url=auth_url, state=state)
 
 
 
 
 
 
 
82
 
83
 
84
  @router.post("/callback", response_model=GoogleOAuthTokenResponse,
 
55
  return HTTPException(status_code=exc.status_code, detail=exc.message)
56
 
57
 
58
+ # Google's basic OpenID profile scopes. A "Testing" consent screen does NOT
59
+ # apply the 7-day refresh-token expiry when only these scopes are requested.
60
+ _BASIC_PROFILE_SCOPES = frozenset({
61
+ "openid",
62
+ "email",
63
+ "profile",
64
+ "https://www.googleapis.com/auth/userinfo.email",
65
+ "https://www.googleapis.com/auth/userinfo.profile",
66
+ })
67
+
68
+
69
+ def _refresh_token_warning(*, access_type: Optional[str], scope: str) -> Optional[str]:
70
+ """Return a user-facing warning about the refresh token this flow will issue.
71
+
72
+ Mirrors Google's documented refresh-token expiration rules:
73
+ https://developers.google.com/identity/protocols/oauth2#expiration
74
+ """
75
+ if access_type != "offline":
76
+ return (
77
+ "No refresh token will be issued because access_type is not 'offline'. "
78
+ "Set access_type to 'offline' to receive a long-lived refresh token "
79
+ "(issued only on the user's first authorization)."
80
+ )
81
+
82
+ requested_scopes = {s.strip() for s in scope.split() if s.strip()}
83
+ testing_note = ""
84
+ if not requested_scopes.issubset(_BASIC_PROFILE_SCOPES):
85
+ testing_note = (
86
+ " However, it expires after 7 days if the OAuth consent screen is in "
87
+ "'Testing' publishing status."
88
+ )
89
+ return (
90
+ "The refresh token is long-lived and does not expire on its own."
91
+ ) + testing_note
92
+
93
+
94
  @router.post("/auth-url", response_model=GoogleOAuthAuthUrlResponse,
95
  summary="Generate a Google OAuth authorization URL (Step 1)")
96
  async def create_auth_url(
 
114
  body.client_id[:8],
115
  (time.perf_counter() - start) * 1000,
116
  )
117
+ return GoogleOAuthAuthUrlResponse(
118
+ success=True,
119
+ auth_url=auth_url,
120
+ state=state,
121
+ warning=_refresh_token_warning(
122
+ access_type=body.access_type, scope=body.scope
123
+ ),
124
+ )
125
 
126
 
127
  @router.post("/callback", response_model=GoogleOAuthTokenResponse,
app/models/schemas.py CHANGED
@@ -915,6 +915,9 @@ class GoogleOAuthAuthUrlResponse(BaseModel):
915
  success: bool
916
  auth_url: str
917
  state: str
 
 
 
918
  error: Optional[str] = None
919
 
920
 
 
915
  success: bool
916
  auth_url: str
917
  state: str
918
+ warning: Optional[str] = Field(
919
+ None, description="User-facing warning describing refresh-token issuance and validity"
920
+ )
921
  error: Optional[str] = None
922
 
923