Skip to content

feat(auth): open the OAuth URL in the default browser - #888

Open
sjawhar wants to merge 1 commit into
googleworkspace:mainfrom
sjawhar:feat/auth-login-open-browser
Open

feat(auth): open the OAuth URL in the default browser#888
sjawhar wants to merge 1 commit into
googleworkspace:mainfrom
sjawhar:feat/auth-login-open-browser

Conversation

@sjawhar

@sjawhar sjawhar commented Jul 30, 2026

Copy link
Copy Markdown

Description

This supersedes #875, which went stale before its review feedback was addressed.

gws auth login currently prints the OAuth URL and waits — on a remote or headless machine that means manually copying the URL and manually forwarding the ephemeral localhost callback port. This PR makes both login flows attempt to open the URL in a browser, keeping the printed URL as the copy-paste fallback:

  • Honors $BROWSER first when set (treated as a single command, not a shell line).
  • Otherwise xdg-open on Linux, open on macOS, explorer on Windows.
  • The opener is spawned detached and reaped on a background thread, so a slow or missing opener can never block the callback server or fail the login.
  • Prints Opening in your browser... only when an opener actually spawned; the existing URL output is unchanged either way (tools and wrappers parse it).
  • Covers both the proxy-aware flow (login_with_proxy_support) and the yup-oauth2 InstalledFlowDelegate.
  • Refuses to pass unsafe values to an opener: non-https schemes, control/whitespace/dangerous-Unicode characters, quotes, backslashes, and shell metacharacters — addressing the Gemini review feedback on feat(auth): open OAuth URL in default browser automatically #875. explorer rather than rundll32 on Windows addresses the EDR concern raised there. No new dependency.

Two small riders needed for a green CI run, called out so they don't surprise anyone:

  • helpers/script.rs: clippy 1.97 (current stable) rejects a nested if inside a match on unmodified main, so cargo clippy --workspace -- -D warnings fails before this PR changes anything. Collapsed into a guarded match arm, behavior-preserving and covered by the existing tests.
  • auth.rs tests: test_load_credentials_encrypted_file set GOOGLE_WORKSPACE_CLI_CONFIG_DIR with a bare set_var and never restored it, leaking a dropped tempdir path into later tests — config_dir_returns_gws_subdir failed roughly 1 in 6 local runs on unmodified main. Now uses the test module's own EnvVarGuard; 10 consecutive clean runs after.

Dry Run Output:

Not applicable — this changes the OAuth login flow, not an API request body.

Test evidence

$ cargo fmt --all -- --check          # exit 0
$ cargo clippy --workspace -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.22s
$ cargo test --workspace
    799 passed; 0 failed (repeated x10 for the flake fix: 10/10 clean)

New unit tests cover opener selection ($BROWSER precedence, per-OS defaults, unknown platform) and URL validation (accepts https OAuth URLs; rejects whitespace, control characters, RTL-override/zero-width Unicode, quotes, backslashes, and shell metacharacters).

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.

@changeset-bot

changeset-bot Bot commented Jul 30, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: af57b34

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 Minor

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

@googleworkspace-bot googleworkspace-bot added area: auth area: core Core CLI parsing, commands, error handling, utilities labels Jul 30, 2026
@gemini-code-assist

Copy link
Copy Markdown
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 enhances the user experience for the gws auth login flow by automatically opening the authentication URL in the user's default browser. It introduces a robust, platform-aware mechanism to spawn browser processes safely while maintaining compatibility with headless environments. The changes include comprehensive security validations for URLs and minor stability improvements to the test suite and codebase.

Highlights

  • Automated Browser Launch: The gws auth login command now automatically attempts to open the OAuth URL in the system's default browser, with the existing manual copy-paste URL remaining as a fallback.
  • Platform-Specific Opener Support: Added support for $BROWSER environment variable, xdg-open (Linux), open (macOS), and explorer (Windows) to handle URL opening securely.
  • Security and Reliability: Implemented strict URL validation to prevent shell injection and unsafe character execution, and ensured the browser process is spawned detached to prevent blocking the CLI.
  • Test and Stability Fixes: Resolved a flaky test in auth.rs by using EnvVarGuard and refactored helpers/script.rs to satisfy clippy requirements.
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 the 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 counterproductive. 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.

Footnotes

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

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

Copy link
Copy Markdown
Contributor

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 introduces automatic browser opening for OAuth login URLs across Linux, macOS, and Windows, with a fallback to copy-pasting. It also fixes an environment variable leak in tests and refactors a match arm in script.rs. The feedback suggests using std::thread::Builder::new().spawn() instead of std::thread::spawn to handle potential thread spawning failures gracefully and prevent application panics.

Comment on lines +134 to +139
Ok(mut child) => {
std::thread::spawn(move || {
let _ = child.wait();
});
true
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Using std::thread::spawn can panic and crash the entire CLI application if the operating system fails to spawn a new thread (e.g., due to resource exhaustion or thread limits). Since this is a CLI tool that may run in resource-constrained environments (like containers or remote servers), it is safer to use std::thread::Builder::new().spawn() which returns a Result and handle any failure gracefully without panicking.

        Ok(mut child) => {
            let _ = std::thread::Builder::new()
                .name("gws-browser-reaper".to_string())
                .spawn(move || {
                    let _ = child.wait();
                });
            true
        }

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done in af57b34thread::Builder::spawn with the error discarded: if the OS refuses the reaper thread, the child just goes unreaped until this short-lived CLI exits, and the login is unaffected.

gws auth login now attempts to open the authorization URL - $BROWSER first,
otherwise the platform opener - while keeping the printed URL as the
copy-paste fallback. Applies to both the proxy-aware flow and the yup-oauth2
flow delegate. Supersedes googleworkspace#875.

Also unbreaks CI on current stable (clippy 1.97 rejects a nested if in
helpers/script.rs on unmodified main) and fixes a 1-in-6 test flake
(a bare set_var leaked GOOGLE_WORKSPACE_CLI_CONFIG_DIR into later tests;
now uses the module's own EnvVarGuard).
@legion-implementer
legion-implementer Bot force-pushed the feat/auth-login-open-browser branch from 7332621 to af57b34 Compare July 30, 2026 13:01
@googleworkspace-bot

Copy link
Copy Markdown
Collaborator

/gemini review

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

Copy link
Copy Markdown
Contributor

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 introduces a feature to automatically open OAuth login URLs in the system's default browser with a copy-paste fallback. It implements OS-specific browser commands (using xdg-open on Linux, open on macOS, and explorer on Windows) and includes URL validation to prevent shell injection or other security issues. Additionally, it improves test isolation by using an environment variable guard and refactors a match statement in the script helper. There are no review comments, and I have no feedback to provide.

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

Labels

area: auth area: core Core CLI parsing, commands, error handling, utilities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants