gws gmail +read fails with:
Your application is authenticating by using local Application Default Credentials.
The gmail.googleapis.com API requires a quota project, which is not set by default.
The equivalent raw command succeeds:
gws gmail users messages get --params '{"userId":"me","id":"<id>","format":"full"}'
Cause
Google identifies tokens from the Cloud SDK client (764086051850-...) as ADC and requires the x-goog-user-project header. Standard resource commands go through executor.rs, which calls auth::get_quota_project() and adds the header. The +read helper bypasses executor.rs and calls fetch_message_metadata directly via crate::client::build_client() and send_with_retry. The request goes out with .bearer_auth(token) only, no quota project header.
This gap exists because #242 moved the x-goog-user-project injection from build_client() into executor.rs. When +read was added in #526, it called build_client() directly and missed the header.
Reproduction
gws auth login # default scopes (gmail.modify)
gws gmail +read --id <any-message-id>
# -> 403 accessNotConfigured
gws gmail users messages get --params '{"userId":"me","id":"<id>","format":"full"}'
# -> succeeds
Adding gmail.readonly to the token does not help — the scope is irrelevant. The missing header is the sole cause.
Related
Suggested fix
Add x-goog-user-project via auth::get_quota_project() in fetch_message_metadata (and other helper functions that bypass executor.rs). Same trade-off as #729 applies.
Alternatively, refactor helpers to route through executor.rs or a shared request-building function that handles auth headers consistently.
Workaround
gws gmail users messages get --params '{"userId":"me","id":"<message-id>","format":"full"}'
Environment
- gws 0.22.5, macOS (Apple Silicon)
- Auth: OAuth desktop, keyring backend
- Confirmed with both
gmail.modify only and gmail.modify + gmail.readonly
- ADC
quota_project_id set to a project with Gmail API enabled (irrelevant — build_client() does not propagate it)
gws gmail +readfails with:The equivalent raw command succeeds:
gws gmail users messages get --params '{"userId":"me","id":"<id>","format":"full"}'Cause
Google identifies tokens from the Cloud SDK client (
764086051850-...) as ADC and requires thex-goog-user-projectheader. Standard resource commands go throughexecutor.rs, which callsauth::get_quota_project()and adds the header. The+readhelper bypassesexecutor.rsand callsfetch_message_metadatadirectly viacrate::client::build_client()andsend_with_retry. The request goes out with.bearer_auth(token)only, no quota project header.This gap exists because #242 moved the
x-goog-user-projectinjection frombuild_client()intoexecutor.rs. When+readwas added in #526, it calledbuild_client()directly and missed the header.Reproduction
Adding
gmail.readonlyto the token does not help — the scope is irrelevant. The missing header is the sole cause.Related
x-goog-user-projectfrombuild_client()toexecutor.rs+readbypassingexecutor.rsSuggested fix
Add
x-goog-user-projectviaauth::get_quota_project()infetch_message_metadata(and other helper functions that bypassexecutor.rs). Same trade-off as #729 applies.Alternatively, refactor helpers to route through
executor.rsor a shared request-building function that handles auth headers consistently.Workaround
gws gmail users messages get --params '{"userId":"me","id":"<message-id>","format":"full"}'Environment
gmail.modifyonly andgmail.modify+gmail.readonlyquota_project_idset to a project with Gmail API enabled (irrelevant —build_client()does not propagate it)