Skip to content

Fix auth failures when accounts.json registry is missing#175

Merged
jpoehnelt merged 1 commit intogoogleworkspace:mainfrom
harche:fix/auth-legacy-credentials
Mar 5, 2026
Merged

Fix auth failures when accounts.json registry is missing#175
jpoehnelt merged 1 commit intogoogleworkspace:mainfrom
harche:fix/auth-legacy-credentials

Conversation

@harche
Copy link
Contributor

@harche harche commented Mar 5, 2026

Description

Three related bugs caused all API calls to fail with "Access denied. No credentials provided" even after a successful gws auth login. This happened when the userinfo endpoint couldn't identify the user's email (e.g. due to missing openid/email scopes), causing credentials to be saved to credentials.enc without an accounts.json registry entry — which then got immediately rejected as "legacy" credentials.

Root Causes

  1. resolve_account() rejected valid credentials.enc as "legacy" when accounts.json was absent, bailing with an error instead of falling through to use them.
  2. main.rs silently swallowed all auth errors (Err(_) => (None, AuthMethod::None)), masking real failures behind the generic "no credentials" message.
  3. auth login didn't include openid/email scopes, so fetch_userinfo_email() couldn't identify the user, causing credentials to be saved without an accounts.json entry.

Fixes

  • src/auth.rs: resolve_account() now returns Ok(None) when no registry exists, allowing load_credentials_inner to pick up credentials.enc.
  • src/main.rs: Auth errors are now propagated unless the error is specifically "No credentials found". Real failures (decryption errors, invalid tokens, etc.) are shown to the user.
  • src/auth_commands.rs: handle_login always injects openid and userinfo.email scopes so the user's email can be fetched and registered in accounts.json.

Dry Run Output:

{
  "body": null,
  "dry_run": true,
  "is_multipart_upload": false,
  "method": "GET",
  "query_params": { "maxResults": "1" },
  "url": "https://gmail.googleapis.com/gmail/v1/users/me/messages"
}

Before (broken)

$ gws gmail users messages list --params '{"userId": "me", "maxResults": 3}'
{
  "error": {
    "code": 401,
    "message": "Access denied. No credentials provided...",
    "reason": "authError"
  }
}

After (fixed)

$ gws gmail users messages list --params '{"userId": "me", "maxResults": 3}'
{
  "messages": [
    { "id": "19cbe9da792d0a86", "threadId": "193e10e9a6d45b5c" },
    ...
  ],
  "resultSizeEstimate": 201
}

Checklist:

  • My code follows the AGENTS.md guidelines (no generated google-* crates).
  • I have run cargo fmt --all to format the code perfectly.
  • I have run cargo clippy -- -D warnings and resolved all warnings.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have provided a Changeset file (e.g. via pnpx changeset) to document my changes.

@harche harche requested a review from jpoehnelt as a code owner March 5, 2026 15:43
@changeset-bot
Copy link

changeset-bot bot commented Mar 5, 2026

🦋 Changeset detected

Latest commit: 6a5efcb

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@googleworkspace/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@google-cla
Copy link

google-cla bot commented Mar 5, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses critical authentication failures that occurred when the accounts.json registry was absent. It resolves three interconnected bugs: allowing the system to correctly utilize existing credentials.enc files, ensuring that authentication errors are properly reported to the user instead of being masked, and guaranteeing that necessary identity scopes are always requested during the login process. These changes significantly improve the robustness and user experience of the authentication flow, preventing all API calls from failing with generic "Access denied" messages.

Highlights

  • Legacy Credential Handling: Modified resolve_account to correctly handle credentials.enc when accounts.json is missing, preventing "legacy" credential rejection and allowing the system to use existing encrypted credentials.
  • Improved Error Reporting: Updated main.rs to propagate specific authentication errors (e.g., decryption failures, invalid tokens) instead of silently falling back to unauthenticated, providing clearer and more actionable feedback to the user.
  • Mandatory Scopes for Login: Ensured gws auth login always requests openid and userinfo.email scopes. This guarantees that the user's email can be fetched and properly registered in accounts.json, preventing future authentication issues.
Changelog
  • .changeset/fix-auth-legacy-credentials.md
    • Added a new changeset file documenting the fix for authentication failures related to missing accounts.json and legacy credentials.
  • src/auth.rs
    • Modified resolve_account to return Ok(None) when no account registry exists, allowing the system to fall back to credentials.enc.
    • Removed the explicit anyhow::bail! for legacy credentials when accounts.json is missing.
    • Added test_resolve_account_no_registry_no_account_returns_none to verify the new behavior.
    • Added test_load_credentials_encrypted_file to test loading encrypted credentials.
    • Added test_load_credentials_encrypted_takes_priority_over_default to ensure encrypted credentials are prioritized.
  • src/auth_commands.rs
    • Changed scopes variable to mutable (let mut scopes).
    • Ensured openid and https://www.googleapis.com/auth/userinfo.email scopes are always included during handle_login.
    • Added new test cases for mask_secret function, covering long, short, and boundary string lengths.
  • src/executor.rs
    • Added test_handle_error_response_401_with_oauth_does_not_mask_error to verify that 401 errors are not masked when OAuth is used.
  • src/main.rs
    • Modified the error handling for auth::get_token to propagate authentication errors (e.g., decryption failures) instead of silently falling back to unauthenticated.
    • Only falls back to unauthenticated if the error message explicitly indicates "No credentials found".
Activity
  • No human activity has occurred on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively addresses three related authentication bugs that led to API failures when an accounts.json registry was missing. The changes correctly adjust credential resolution to fall back to legacy credentials.enc, ensure openid and email scopes are always included during login for proper account registration, and improve error propagation so that real authentication failures are no longer silently ignored. The added tests provide good coverage for the new logic. I have one suggestion to make the error handling in main.rs more robust.

Note: Security Review did not run due to the size of the PR.

@jpoehnelt
Copy link
Member

Needs rebase for conflicts. Prefer {attribution.commit: ""} for usage of Claude on Google repositories for CLA.

@harche harche force-pushed the fix/auth-legacy-credentials branch 3 times, most recently from 083f620 to 68777e9 Compare March 5, 2026 16:33
@harche
Copy link
Contributor Author

harche commented Mar 5, 2026

Needs rebase for conflicts. Prefer {attribution.commit: ""} for usage of Claude on Google repositories for CLA.

Thanks @jpoehnelt , does that look okay now?

@harche harche force-pushed the fix/auth-legacy-credentials branch from 68777e9 to 8e21db6 Compare March 5, 2026 17:21
Three related bugs caused all API calls to fail with "Access denied.
No credentials provided" even after successful `gws auth login`:

1. resolve_account() rejected valid credentials.enc as "legacy" when
   accounts.json was absent, instead of falling through to use them.

2. main.rs silently swallowed all auth errors (Err(_) => None),
   masking real failures behind a generic "no credentials" message.

3. auth login didn't include openid/email scopes, so
   fetch_userinfo_email() couldn't identify the user, causing
   credentials to be saved without an accounts.json entry.

{attribution.commit: ""}
@harche harche force-pushed the fix/auth-legacy-credentials branch from 8e21db6 to 6a5efcb Compare March 5, 2026 17:22
@jpoehnelt jpoehnelt added area: auth cla: yes This human has signed the Contributor License Agreement. complexity: medium Moderate change, some review needed labels Mar 5, 2026
@jpoehnelt jpoehnelt merged commit a926e3f into googleworkspace:main Mar 5, 2026
23 checks passed
jpoehnelt pushed a commit that referenced this pull request Mar 5, 2026
- Update stale docstring on resolve_account to reflect fallthrough behavior
- Add breadcrumb comment on string-based error matching in main.rs
- Move identity scope injection before authenticator build for readability
jpoehnelt added a commit that referenced this pull request Mar 5, 2026
- Update stale docstring on resolve_account to reflect fallthrough behavior
- Add breadcrumb comment on string-based error matching in main.rs
- Move identity scope injection before authenticator build for readability

Co-authored-by: jpoehnelt-bot <jpoehnelt-bot@users.noreply.github.com>
@harche harche deleted the fix/auth-legacy-credentials branch March 5, 2026 22:38
@codecov
Copy link

codecov bot commented Mar 5, 2026

Codecov Report

❌ Patch coverage is 86.53846% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 56.80%. Comparing base (473dd30) to head (6a5efcb).
⚠️ Report is 23 commits behind head on main.

Files with missing lines Patch % Lines
src/auth_commands.rs 66.66% 6 Missing ⚠️
src/main.rs 0.00% 5 Missing ⚠️
src/executor.rs 86.36% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #175      +/-   ##
==========================================
+ Coverage   56.21%   56.80%   +0.58%     
==========================================
  Files          38       38              
  Lines       13853    13950      +97     
==========================================
+ Hits         7788     7924     +136     
+ Misses       6065     6026      -39     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: auth cla: yes This human has signed the Contributor License Agreement. complexity: medium Moderate change, some review needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants