feat: expand Gmail OAuth scopes, unify Google callback URL, store Gmail creds on login
- Add gmail.readonly to GMAIL_SCOPES (gmail_service) and GMAIL_API_SCOPES (providers) so users().getProfile() no longer returns 403 insufficientPermissions - Consolidate Gmail scope list: GMAIL_SCOPES in gmail_service.py is the single source of truth; auth.py and providers.py now import and spread it - Add include_granted_scopes=true to both Gmail and login authorize URLs so scope additions take effect for previously-connected users - Add state=gmail_connect to the Gmail authorize URL; the shared /auth/callback page routes to gmailApi.saveCallback() when this state is present, otherwise falls through to the normal login flow - Google Sign-In authorize URL now requests all six scopes (openid, email, profile + 3 Gmail scopes) with access_type=offline, prompt=consent, and include_granted_scopes=true - POST /auth/google now stores Gmail credentials automatically after sign-in (non-fatal: login succeeds even if credential storage fails) - Settings Connect Gmail button now uses /auth/callback instead of /auth/gmail-callback - only ONE redirect URI needed in Google Cloud Console - URL-encode scope parameter in both authorize URL builders - Update auth_service._register_google scope to include all Gmail scopes - Update CHANGELOG.md and docs/TODO.md Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com> Agent-Logs-Url: https://github.com/christianlouis/pop_puller_to_gmail/sessions/d6e2de8b-088d-46f3-8127-137245c3ecdd
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import List, Optional
|
||||
from urllib.parse import quote as urlquote
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select
|
||||
@@ -21,17 +22,18 @@ from app.models.schemas import (
|
||||
GmailAuthorizeResponse,
|
||||
GmailCallbackRequest,
|
||||
)
|
||||
from app.services.gmail_service import GmailService
|
||||
from app.services.gmail_service import GmailService, GMAIL_SCOPES
|
||||
|
||||
router = APIRouter()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Gmail API scopes needed for email injection
|
||||
# Gmail API scopes requested during the "Connect Gmail" OAuth flow.
|
||||
# GMAIL_SCOPES (gmail.insert, gmail.labels, gmail.readonly) are imported from
|
||||
# gmail_service so the scope list stays in sync with what GmailService uses.
|
||||
GMAIL_API_SCOPES = [
|
||||
"openid",
|
||||
"email",
|
||||
"https://www.googleapis.com/auth/gmail.insert",
|
||||
"https://www.googleapis.com/auth/gmail.labels",
|
||||
*GMAIL_SCOPES,
|
||||
]
|
||||
|
||||
# Provider presets with server configurations
|
||||
@@ -302,7 +304,7 @@ async def get_gmail_authorize_url(
|
||||
detail="Google OAuth2 is not configured on this server.",
|
||||
)
|
||||
|
||||
scope = " ".join(GMAIL_API_SCOPES)
|
||||
scope = urlquote(" ".join(GMAIL_API_SCOPES))
|
||||
url = (
|
||||
"https://accounts.google.com/o/oauth2/v2/auth"
|
||||
f"?client_id={settings.GOOGLE_CLIENT_ID}"
|
||||
@@ -311,6 +313,8 @@ async def get_gmail_authorize_url(
|
||||
f"&redirect_uri={redirect_uri}"
|
||||
"&access_type=offline"
|
||||
"&prompt=consent"
|
||||
"&include_granted_scopes=true"
|
||||
"&state=gmail_connect"
|
||||
)
|
||||
return GmailAuthorizeResponse(authorization_url=url)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user