llm-ready-data / app /services /google_scope_map.py
validops-east-1's picture
feat: friendly oauth scope map and sheets spreadsheet delete/list
a980424
Raw
History Blame Contribute Delete
29.4 kB
from __future__ import annotations
from typing import Dict, List, Optional, Tuple
# Friendly Google OAuth scope map.
#
# ``SCOPE_MAP`` groups every Google OAuth scope under a human-friendly category
# and gives each scope a short alias. Clients can request scopes by alias in
# POST /google/oauth/auth-url instead of pasting long scope URIs, e.g.
# ``["openid", "email", "gmail_full"]``.
#
# Generic full scope URIs are also accepted verbatim (the map is a convenience,
# not a restriction). Validation only rejects empty/unknown scope names.
SCOPE_MAP: Dict[str, Dict[str, str]] = {
"authentication": {
"openid": "openid",
"email": "https://www.googleapis.com/auth/userinfo.email",
"profile": "https://www.googleapis.com/auth/userinfo.profile",
"userinfo_email": "https://www.googleapis.com/auth/userinfo.email",
"userinfo_profile": "https://www.googleapis.com/auth/userinfo.profile",
},
"gmail": {
"gmail_full": "https://www.googleapis.com/auth/gmail.modify",
"gmail_readonly": "https://www.googleapis.com/auth/gmail.readonly",
"gmail_send": "https://www.googleapis.com/auth/gmail.send",
"gmail_compose": "https://www.googleapis.com/auth/gmail.compose",
"gmail_metadata": "https://www.googleapis.com/auth/gmail.metadata",
"gmail_insert": "https://www.googleapis.com/auth/gmail.insert",
"gmail_labels": "https://www.googleapis.com/auth/gmail.labels",
"gmail_settings_basic": "https://www.googleapis.com/auth/gmail.settings.basic",
"gmail_settings_sharing": "https://www.googleapis.com/auth/gmail.settings.sharing",
"gmail_permanent_delete": "https://mail.google.com/",
"gmail_addons_current_action_compose": "https://www.googleapis.com/auth/gmail.addons.current.action.compose",
"gmail_addons_current_message_action": "https://www.googleapis.com/auth/gmail.addons.current.message.action",
"gmail_addons_current_message_metadata": "https://www.googleapis.com/auth/gmail.addons.current.message.metadata",
"gmail_addons_current_message_readonly": "https://www.googleapis.com/auth/gmail.addons.current.message.readonly",
},
"google_sheets": {
"sheets_readwrite": "https://www.googleapis.com/auth/spreadsheets",
"sheets_readonly": "https://www.googleapis.com/auth/spreadsheets.readonly",
"sheets_drive_file": "https://www.googleapis.com/auth/drive.file",
"sheets_drive_readonly": "https://www.googleapis.com/auth/drive.readonly",
"sheets_drive_full": "https://www.googleapis.com/auth/drive",
},
"google_drive": {
"drive_file": "https://www.googleapis.com/auth/drive.file",
"drive_metadata_readonly": "https://www.googleapis.com/auth/drive.metadata.readonly",
"drive_readonly": "https://www.googleapis.com/auth/drive.readonly",
"drive_full": "https://www.googleapis.com/auth/drive",
"drive_metadata": "https://www.googleapis.com/auth/drive.metadata",
"drive_appdata": "https://www.googleapis.com/auth/drive.appdata",
"drive_apps_readonly": "https://www.googleapis.com/auth/drive.apps.readonly",
"drive_scripts": "https://www.googleapis.com/auth/drive.scripts",
"drive_install": "https://www.googleapis.com/auth/drive.install",
"drive_activity": "https://www.googleapis.com/auth/drive.activity",
"drive_activity_readonly": "https://www.googleapis.com/auth/drive.activity.readonly",
"drive_photos_readonly": "https://www.googleapis.com/auth/drive.photos.readonly",
"drive_meet_readonly": "https://www.googleapis.com/auth/drive.meet.readonly",
},
"google_docs": {
"docs_readwrite": "https://www.googleapis.com/auth/documents",
"docs_readonly": "https://www.googleapis.com/auth/documents.readonly",
"docs_drive_file": "https://www.googleapis.com/auth/drive.file",
"docs_drive_readonly": "https://www.googleapis.com/auth/drive.readonly",
"docs_drive_full": "https://www.googleapis.com/auth/drive",
},
"google_slides": {
"slides_readwrite": "https://www.googleapis.com/auth/presentations",
"slides_readonly": "https://www.googleapis.com/auth/presentations.readonly",
"slides_drive_file": "https://www.googleapis.com/auth/drive.file",
"slides_drive_readonly": "https://www.googleapis.com/auth/drive.readonly",
"slides_drive_full": "https://www.googleapis.com/auth/drive",
},
"google_calendar": {
"calendar_full": "https://www.googleapis.com/auth/calendar",
"calendar_readonly": "https://www.googleapis.com/auth/calendar.readonly",
"calendar_events": "https://www.googleapis.com/auth/calendar.events",
"calendar_events_readonly": "https://www.googleapis.com/auth/calendar.events.readonly",
"calendar_events_owned": "https://www.googleapis.com/auth/calendar.events.owned",
"calendar_events_owned_readonly": "https://www.googleapis.com/auth/calendar.events.owned.readonly",
"calendar_events_public_readonly": "https://www.googleapis.com/auth/calendar.events.public.readonly",
"calendar_events_freebusy": "https://www.googleapis.com/auth/calendar.events.freebusy",
"calendar_freebusy": "https://www.googleapis.com/auth/calendar.freebusy",
"calendar_settings_readonly": "https://www.googleapis.com/auth/calendar.settings.readonly",
"calendar_calendarlist": "https://www.googleapis.com/auth/calendar.calendarlist",
"calendar_calendarlist_readonly": "https://www.googleapis.com/auth/calendar.calendarlist.readonly",
"calendar_calendars": "https://www.googleapis.com/auth/calendar.calendars",
"calendar_calendars_readonly": "https://www.googleapis.com/auth/calendar.calendars.readonly",
"calendar_acls": "https://www.googleapis.com/auth/calendar.acls",
"calendar_acls_readonly": "https://www.googleapis.com/auth/calendar.acls.readonly",
"calendar_app_created": "https://www.googleapis.com/auth/calendar.app.created",
"calendar_addons_execute": "https://www.googleapis.com/auth/calendar.addons.execute",
"calendar_addons_current_event_read": "https://www.googleapis.com/auth/calendar.addons.current.event.read",
"calendar_addons_current_event_write": "https://www.googleapis.com/auth/calendar.addons.current.event.write",
},
"google_contacts": {
"contacts_full": "https://www.googleapis.com/auth/contacts",
"contacts_readonly": "https://www.googleapis.com/auth/contacts.readonly",
"contacts_other_readonly": "https://www.googleapis.com/auth/contacts.other.readonly",
"contacts_directory_readonly": "https://www.googleapis.com/auth/directory.readonly",
},
"google_tasks": {
"tasks_readwrite": "https://www.googleapis.com/auth/tasks",
"tasks_readonly": "https://www.googleapis.com/auth/tasks.readonly",
},
"google_photos": {
"photos_library_full": "https://www.googleapis.com/auth/photoslibrary",
"photos_library_readonly": "https://www.googleapis.com/auth/photoslibrary.readonly",
"photos_library_appendonly": "https://www.googleapis.com/auth/photoslibrary.appendonly",
"photos_library_edit_appcreated": "https://www.googleapis.com/auth/photoslibrary.edit.appcreateddata",
"photos_library_readonly_appcreated": "https://www.googleapis.com/auth/photoslibrary.readonly.appcreateddata",
"photos_library_sharing": "https://www.googleapis.com/auth/photoslibrary.sharing",
},
"google_chat": {
"chat_messages": "https://www.googleapis.com/auth/chat.messages",
"chat_messages_readonly": "https://www.googleapis.com/auth/chat.messages.readonly",
"chat_spaces": "https://www.googleapis.com/auth/chat.spaces",
"chat_spaces_readonly": "https://www.googleapis.com/auth/chat.spaces.readonly",
"chat_import": "https://www.googleapis.com/auth/chat.import",
"chat_apps_configuration": "https://www.googleapis.com/auth/chat.apps.configuration",
"chat_apps_configuration_readonly": "https://www.googleapis.com/auth/chat.apps.configuration.readonly",
"chat_apps_readonly": "https://www.googleapis.com/auth/chat.apps.readonly",
"chat_pushes": "https://www.googleapis.com/auth/chat.pushes",
"chat_meetings": "https://www.googleapis.com/auth/chat.meetings",
"chat_meetings_readonly": "https://www.googleapis.com/auth/chat.meetings.readonly",
},
"google_meet": {
"meet_recordings_readonly": "https://www.googleapis.com/auth/drive.meet.readonly",
},
"google_forms": {
"forms_full": "https://www.googleapis.com/auth/forms",
"forms_responses_readonly": "https://www.googleapis.com/auth/forms.responses.readonly",
},
"google_classroom": {
"classroom_courses": "https://www.googleapis.com/auth/classroom.courses",
"classroom_courses_readonly": "https://www.googleapis.com/auth/classroom.courses.readonly",
"classroom_rosters": "https://www.googleapis.com/auth/classroom.rosters",
"classroom_rosters_readonly": "https://www.googleapis.com/auth/classroom.rosters.readonly",
"classroom_profile_emails": "https://www.googleapis.com/auth/classroom.profile.emails",
"classroom_profile_photos": "https://www.googleapis.com/auth/classroom.profile.photos",
"classroom_announcements": "https://www.googleapis.com/auth/classroom.announcements",
"classroom_announcements_readonly": "https://www.googleapis.com/auth/classroom.announcements.readonly",
"classroom_topics": "https://www.googleapis.com/auth/classroom.topics",
"classroom_topics_readonly": "https://www.googleapis.com/auth/classroom.topics.readonly",
"classroom_coursework_students": "https://www.googleapis.com/auth/classroom.coursework.students",
"classroom_coursework_students_readonly": "https://www.googleapis.com/auth/classroom.coursework.students.readonly",
"classroom_coursework_me": "https://www.googleapis.com/auth/classroom.coursework.me",
"classroom_coursework_me_readonly": "https://www.googleapis.com/auth/classroom.coursework.me.readonly",
"classroom_courseworkmaterials": "https://www.googleapis.com/auth/classroom.courseworkmaterials",
"classroom_courseworkmaterials_readonly": "https://www.googleapis.com/auth/classroom.courseworkmaterials.readonly",
"classroom_guardianlinks_students": "https://www.googleapis.com/auth/classroom.guardianlinks.students",
"classroom_guardianlinks_students_readonly": "https://www.googleapis.com/auth/classroom.guardianlinks.students.readonly",
"classroom_student_submissions_me_readonly": "https://www.googleapis.com/auth/classroom.student-submissions.me.readonly",
"classroom_student_submissions_students_readonly": "https://www.googleapis.com/auth/classroom.student-submissions.students.readonly",
},
"google_analytics": {
"analytics_full": "https://www.googleapis.com/auth/analytics",
"analytics_readonly": "https://www.googleapis.com/auth/analytics.readonly",
"analytics_edit": "https://www.googleapis.com/auth/analytics.edit",
"analytics_manage_users": "https://www.googleapis.com/auth/analytics.manage.users",
"analytics_manage_users_readonly": "https://www.googleapis.com/auth/analytics.manage.users.readonly",
"analytics_manage_edit": "https://www.googleapis.com/auth/analytics.manage.edit",
"analytics_manage_partners": "https://www.googleapis.com/auth/analytics.manage.partners",
"analytics_provision": "https://www.googleapis.com/auth/analytics.provision",
},
"google_ads": {
"google_ads_full": "https://www.googleapis.com/auth/adwords",
"admanager_readonly": "https://www.googleapis.com/auth/admanager.readonly",
},
"google_cloud": {
"bigquery_readonly": "https://www.googleapis.com/auth/bigquery.readonly",
"bigquery_full": "https://www.googleapis.com/auth/bigquery",
"bigquery_insertdata": "https://www.googleapis.com/auth/bigquery.insertdata",
"cloud_platform": "https://www.googleapis.com/auth/cloud-platform",
"cloud_platform_readonly": "https://www.googleapis.com/auth/cloud-platform.read-only",
"devstorage_read_only": "https://www.googleapis.com/auth/devstorage.read_only",
"devstorage_read_write": "https://www.googleapis.com/auth/devstorage.read_write",
"devstorage_full_control": "https://www.googleapis.com/auth/devstorage.full_control",
"compute_readonly": "https://www.googleapis.com/auth/compute.readonly",
"compute_full": "https://www.googleapis.com/auth/compute",
"datastore": "https://www.googleapis.com/auth/datastore",
"sqlservice_admin": "https://www.googleapis.com/auth/sqlservice.admin",
"vision": "https://www.googleapis.com/auth/cloud-vision",
"translate": "https://www.googleapis.com/auth/cloud-translation",
"language": "https://www.googleapis.com/auth/cloud-language",
"genai": "https://www.googleapis.com/auth/genai",
},
"google_maps": {},
"youtube": {
"youtube_readonly": "https://www.googleapis.com/auth/youtube.readonly",
"youtube_full": "https://www.googleapis.com/auth/youtube",
"youtube_upload": "https://www.googleapis.com/auth/youtube.upload",
"youtube_force_ssl": "https://www.googleapis.com/auth/youtube.force-ssl",
"youtube_channel_memberships_creator": "https://www.googleapis.com/auth/youtube.channel-memberships.creator",
"youtube_partner": "https://www.googleapis.com/auth/youtubepartner",
"youtube_partner_channel_audit": "https://www.googleapis.com/auth/youtubepartner-channel-audit",
},
"google_play": {
"play_androidpublisher": "https://www.googleapis.com/auth/androidpublisher",
"play_games": "https://www.googleapis.com/auth/playgames",
"play_games_readonly": "https://www.googleapis.com/auth/playgames.readonly",
},
"firebase": {
"firebase_full": "https://www.googleapis.com/auth/firebase",
"firebase_readonly": "https://www.googleapis.com/auth/firebase.readonly",
"firebase_database": "https://www.googleapis.com/auth/firebase.database",
"firebase_database_readonly": "https://www.googleapis.com/auth/firebase.database.readonly",
"firebase_messaging": "https://www.googleapis.com/auth/firebase.messaging",
"firebase_rules": "https://www.googleapis.com/auth/firebase.rules",
"firebase_rules_readonly": "https://www.googleapis.com/auth/firebase.rules.readonly",
"firebase_analytics": "https://www.googleapis.com/auth/firebase.analytics",
},
"admin_sdk": {
"admin_directory_user_readonly": "https://www.googleapis.com/auth/admin.directory.user.readonly",
"admin_directory_user": "https://www.googleapis.com/auth/admin.directory.user",
"admin_directory_group_readonly": "https://www.googleapis.com/auth/admin.directory.group.readonly",
"admin_directory_group": "https://www.googleapis.com/auth/admin.directory.group",
"admin_directory_group_member_readonly": "https://www.googleapis.com/auth/admin.directory.group.member.readonly",
"admin_directory_group_member": "https://www.googleapis.com/auth/admin.directory.group.member",
"admin_directory_device_chromeos_readonly": "https://www.googleapis.com/auth/admin.directory.device.chromeos.readonly",
"admin_directory_device_chromeos": "https://www.googleapis.com/auth/admin.directory.device.chromeos",
"admin_directory_orgunit_readonly": "https://www.googleapis.com/auth/admin.directory.orgunit.readonly",
"admin_directory_orgunit": "https://www.googleapis.com/auth/admin.directory.orgunit",
"admin_directory_rolemanagement_readonly": "https://www.googleapis.com/auth/admin.directory.rolemanagement.readonly",
"admin_directory_rolemanagement": "https://www.googleapis.com/auth/admin.directory.rolemanagement",
"admin_directory_domain_readonly": "https://www.googleapis.com/auth/admin.directory.domain.readonly",
"admin_directory_customer_readonly": "https://www.googleapis.com/auth/admin.directory.customer.readonly",
"admin_directory_userschema_readonly": "https://www.googleapis.com/auth/admin.directory.userschema.readonly",
"admin_reports_audit_readonly": "https://www.googleapis.com/auth/admin.reports.audit.readonly",
"admin_reports_usage_readonly": "https://www.googleapis.com/auth/admin.reports.usage.readonly",
"admin_datatransfer": "https://www.googleapis.com/auth/admin.datatransfer",
},
"people_api": {
"people_contacts_full": "https://www.googleapis.com/auth/contacts",
"people_contacts_readonly": "https://www.googleapis.com/auth/contacts.readonly",
"people_othercontacts": "https://www.googleapis.com/auth/people.otherContacts",
"people_othercontacts_readonly": "https://www.googleapis.com/auth/people.otherContacts.readonly",
"people_email_readonly": "https://www.googleapis.com/auth/people.emailAddresses.readonly",
"people_phone_readonly": "https://www.googleapis.com/auth/people.phoneNumbers.readonly",
"people_contactinfo": "https://www.googleapis.com/auth/people.contactInfo",
"people_contactinfo_readonly": "https://www.googleapis.com/auth/people.contactInfo.readonly",
"people_directory_readonly": "https://www.googleapis.com/auth/people.directory.readonly",
"user_emails_readonly": "https://www.googleapis.com/auth/user.emails.readonly",
"user_phonenumbers_readonly": "https://www.googleapis.com/auth/user.phonenumbers.readonly",
},
"business_profile": {
"business_manage": "https://www.googleapis.com/auth/business.manage",
},
"other": {
"openid": "openid",
"email": "https://www.googleapis.com/auth/userinfo.email",
"profile": "https://www.googleapis.com/auth/userinfo.profile",
},
}
CATEGORY_ORDER: List[str] = list(SCOPE_MAP.keys())
ALIAS_TO_URI: Dict[str, str] = {
alias: uri
for category in SCOPE_MAP.values()
for alias, uri in category.items()
}
ALL_ALIASES: List[str] = sorted(ALIAS_TO_URI)
# Scope containment for UX normalization. When a broader scope is already in
# the request, narrower scopes of the same family are redundant and are dropped
# so the Google consent screen stays minimal. Only documented supersets are
# listed; generic/unknown scopes are never touched.
_SCOPE_INCLUDED_BY: Dict[str, Tuple[str, ...]] = {
# --- Gmail family ---
"https://www.googleapis.com/auth/gmail.metadata": (
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/gmail.modify",
"https://mail.google.com/",
),
"https://www.googleapis.com/auth/gmail.readonly": (
"https://www.googleapis.com/auth/gmail.modify",
"https://mail.google.com/",
),
"https://www.googleapis.com/auth/gmail.labels": (
"https://www.googleapis.com/auth/gmail.modify",
"https://mail.google.com/",
),
"https://www.googleapis.com/auth/gmail.send": (
"https://www.googleapis.com/auth/gmail.compose",
"https://www.googleapis.com/auth/gmail.modify",
"https://mail.google.com/",
),
"https://www.googleapis.com/auth/gmail.compose": (
"https://www.googleapis.com/auth/gmail.modify",
"https://mail.google.com/",
),
"https://www.googleapis.com/auth/gmail.modify": (
"https://mail.google.com/",
),
# --- Sheets / Drive family ---
"https://www.googleapis.com/auth/spreadsheets.readonly": (
"https://www.googleapis.com/auth/spreadsheets",
),
"https://www.googleapis.com/auth/drive.metadata.readonly": (
"https://www.googleapis.com/auth/drive.readonly",
"https://www.googleapis.com/auth/drive.metadata",
"https://www.googleapis.com/auth/drive",
),
"https://www.googleapis.com/auth/drive.metadata": (
"https://www.googleapis.com/auth/drive",
),
"https://www.googleapis.com/auth/drive.readonly": (
"https://www.googleapis.com/auth/drive",
),
"https://www.googleapis.com/auth/drive.file": (
"https://www.googleapis.com/auth/drive",
),
"https://www.googleapis.com/auth/drive.appdata": (
"https://www.googleapis.com/auth/drive",
),
"https://www.googleapis.com/auth/drive.scripts": (
"https://www.googleapis.com/auth/drive",
),
"https://www.googleapis.com/auth/drive.activity.readonly": (
"https://www.googleapis.com/auth/drive.activity",
"https://www.googleapis.com/auth/drive",
),
"https://www.googleapis.com/auth/drive.activity": (
"https://www.googleapis.com/auth/drive",
),
"https://www.googleapis.com/auth/drive.photos.readonly": (
"https://www.googleapis.com/auth/drive",
),
"https://www.googleapis.com/auth/drive.meet.readonly": (
"https://www.googleapis.com/auth/drive",
),
# --- Calendar family ---
"https://www.googleapis.com/auth/calendar.events.readonly": (
"https://www.googleapis.com/auth/calendar.events",
"https://www.googleapis.com/auth/calendar.readonly",
"https://www.googleapis.com/auth/calendar",
),
"https://www.googleapis.com/auth/calendar.events": (
"https://www.googleapis.com/auth/calendar",
),
"https://www.googleapis.com/auth/calendar.events.owned.readonly": (
"https://www.googleapis.com/auth/calendar.events.owned",
"https://www.googleapis.com/auth/calendar.events.readonly",
"https://www.googleapis.com/auth/calendar.readonly",
"https://www.googleapis.com/auth/calendar",
),
"https://www.googleapis.com/auth/calendar.events.owned": (
"https://www.googleapis.com/auth/calendar.events",
"https://www.googleapis.com/auth/calendar",
),
"https://www.googleapis.com/auth/calendar.events.public.readonly": (
"https://www.googleapis.com/auth/calendar.readonly",
"https://www.googleapis.com/auth/calendar",
),
"https://www.googleapis.com/auth/calendar.events.freebusy": (
"https://www.googleapis.com/auth/calendar.freebusy",
"https://www.googleapis.com/auth/calendar",
),
"https://www.googleapis.com/auth/calendar.readonly": (
"https://www.googleapis.com/auth/calendar",
),
"https://www.googleapis.com/auth/calendar.freebusy": (
"https://www.googleapis.com/auth/calendar",
),
"https://www.googleapis.com/auth/calendar.settings.readonly": (
"https://www.googleapis.com/auth/calendar",
),
"https://www.googleapis.com/auth/calendar.calendarlist.readonly": (
"https://www.googleapis.com/auth/calendar.calendarlist",
"https://www.googleapis.com/auth/calendar",
),
"https://www.googleapis.com/auth/calendar.calendarlist": (
"https://www.googleapis.com/auth/calendar",
),
"https://www.googleapis.com/auth/calendar.calendars.readonly": (
"https://www.googleapis.com/auth/calendar.calendars",
"https://www.googleapis.com/auth/calendar",
),
"https://www.googleapis.com/auth/calendar.calendars": (
"https://www.googleapis.com/auth/calendar",
),
"https://www.googleapis.com/auth/calendar.acls.readonly": (
"https://www.googleapis.com/auth/calendar.acls",
"https://www.googleapis.com/auth/calendar",
),
"https://www.googleapis.com/auth/calendar.acls": (
"https://www.googleapis.com/auth/calendar",
),
# --- Contacts / People family ---
"https://www.googleapis.com/auth/contacts.readonly": (
"https://www.googleapis.com/auth/contacts",
),
"https://www.googleapis.com/auth/contacts.other.readonly": (
"https://www.googleapis.com/auth/contacts",
),
# --- Tasks family ---
"https://www.googleapis.com/auth/tasks.readonly": (
"https://www.googleapis.com/auth/tasks",
),
# --- YouTube family ---
"https://www.googleapis.com/auth/youtube.readonly": (
"https://www.googleapis.com/auth/youtube.force-ssl",
"https://www.googleapis.com/auth/youtube",
),
"https://www.googleapis.com/auth/youtube.upload": (
"https://www.googleapis.com/auth/youtube",
),
"https://www.googleapis.com/auth/youtube.force-ssl": (
"https://www.googleapis.com/auth/youtube",
),
"https://www.googleapis.com/auth/youtube.channel-memberships.creator": (
"https://www.googleapis.com/auth/youtube",
),
"https://www.googleapis.com/auth/youtubepartner-channel-audit": (
"https://www.googleapis.com/auth/youtubepartner",
),
# --- Forms family ---
"https://www.googleapis.com/auth/forms.responses.readonly": (
"https://www.googleapis.com/auth/forms",
),
# --- Analytics family ---
"https://www.googleapis.com/auth/analytics.readonly": (
"https://www.googleapis.com/auth/analytics.edit",
"https://www.googleapis.com/auth/analytics",
),
"https://www.googleapis.com/auth/analytics.edit": (
"https://www.googleapis.com/auth/analytics",
),
"https://www.googleapis.com/auth/analytics.manage.users.readonly": (
"https://www.googleapis.com/auth/analytics.manage.users",
),
# --- BigQuery / Cloud family ---
"https://www.googleapis.com/auth/bigquery.readonly": (
"https://www.googleapis.com/auth/bigquery",
),
"https://www.googleapis.com/auth/bigquery.insertdata": (
"https://www.googleapis.com/auth/bigquery",
),
"https://www.googleapis.com/auth/cloud-platform.read-only": (
"https://www.googleapis.com/auth/cloud-platform",
),
"https://www.googleapis.com/auth/devstorage.read_only": (
"https://www.googleapis.com/auth/devstorage.read_write",
"https://www.googleapis.com/auth/devstorage.full_control",
),
"https://www.googleapis.com/auth/devstorage.read_write": (
"https://www.googleapis.com/auth/devstorage.full_control",
),
# --- Admin SDK family ---
"https://www.googleapis.com/auth/admin.directory.user.readonly": (
"https://www.googleapis.com/auth/admin.directory.user",
),
"https://www.googleapis.com/auth/admin.directory.group.readonly": (
"https://www.googleapis.com/auth/admin.directory.group",
),
"https://www.googleapis.com/auth/admin.directory.group.member.readonly": (
"https://www.googleapis.com/auth/admin.directory.group.member",
),
"https://www.googleapis.com/auth/admin.directory.device.chromeos.readonly": (
"https://www.googleapis.com/auth/admin.directory.device.chromeos",
),
"https://www.googleapis.com/auth/admin.directory.orgunit.readonly": (
"https://www.googleapis.com/auth/admin.directory.orgunit",
),
"https://www.googleapis.com/auth/admin.directory.rolemanagement.readonly": (
"https://www.googleapis.com/auth/admin.directory.rolemanagement",
),
}
def is_generic_scope(value: str) -> bool:
"""True when the value is a full scope URI the client typed directly."""
return value.startswith(("http://", "https://", "mail.google.com/")) or value == "openid"
def _normalize_scopes(resolved: List[str]) -> Tuple[List[str], List[str]]:
"""Drop scopes already covered by a broader scope in the same request.
Returns ``(kept_scopes, dropped_scopes)``. Order of the remaining scopes is
preserved. Unknown/generic scopes (not in the containment table) are never
dropped.
"""
present = set(resolved)
kept: List[str] = []
dropped: List[str] = []
for uri in resolved:
supersets = _SCOPE_INCLUDED_BY.get(uri, ())
if any(superset in present for superset in supersets):
dropped.append(uri)
continue
kept.append(uri)
return kept, dropped
def resolve_scope_list(
scopes: Optional[List[str]], *, normalize: bool = True
) -> Tuple[List[str], List[str], List[str]]:
"""Resolve a list of scope aliases / URIs into a de-duplicated list of URIs.
Returns ``(resolved_uris, errors, dropped_scopes)``. Generic full scope URIs
are accepted verbatim; only empty or unknown scope names produce errors.
When ``normalize`` is true, narrower scopes that are fully covered by a
broader scope already present are dropped (best UX: minimal consent screen).
"""
resolved: List[str] = []
errors: List[str] = []
dropped: List[str] = []
seen = set()
for raw in scopes or []:
value = str(raw or "").strip()
if not value:
errors.append("Scope name is missing (empty entry).")
continue
if value in ALIAS_TO_URI:
uri = ALIAS_TO_URI[value]
elif is_generic_scope(value):
uri = value
else:
errors.append(
f"Unknown scope '{value}'. It is not a known alias and not a full scope URI. "
f"Valid aliases: {', '.join(ALL_ALIASES)}"
)
continue
if uri not in seen:
seen.add(uri)
resolved.append(uri)
if normalize:
resolved, dropped = _normalize_scopes(resolved)
return resolved, errors, dropped