Skip to content

Conversation

@zhizinan1997
Copy link

Add Manual Callback Input Support for Docker/Remote Authentication

Description

This PR enhances the Gemini OAuth2 authentication flow to support manual callback URL input, which is particularly useful in Docker containers and remote environments where automatic localhost callbacks may not work due to network isolation.

Problem

When running ./CLIProxyAPI --login in Docker:

  1. The system generates an OAuth URL and attempts to open it in a browser
  2. After user authentication, Google redirects to http://localhost:8085/oauth2callback?code=...
  3. However, in Docker containers, this callback cannot reach the container's localhost server
  4. Users are stuck waiting for a callback that will never arrive, with no alternative way to proceed

Solution

This PR modifies internal/auth/gemini/gemini_auth.go to:

  1. Parallel Listening: The authentication flow now simultaneously listens for:

    • Automatic HTTP callback (traditional flow)
    • Manual user input (fallback for Docker/remote)
    • Timeout (5 minutes)
  2. Flexible Code Extraction: The extractCodeFromInput() function intelligently extracts authorization codes from multiple input formats:

    • Full callback URL: http://localhost:8085/oauth2callback?code=xxx&state=yyy
    • Direct authorization code: 4/0AY0e-g7r...
    • Query string format: code=xxx&state=yyy
  3. User-Friendly Instructions: Clear prompts guide users on:

    • What URL to open in their browser
    • How to copy the callback URL after authentication
    • How to paste it into the Docker terminal

Changes

Modified Files

  • internal/auth/gemini/gemini_auth.go

Key Changes

  1. Added bufio and os imports for stdin reading
  2. Modified getTokenFromWeb() to create a goroutine that listens for manual input
  3. Added extractCodeFromInput() helper function to parse various input formats
  4. Updated user prompts to explain both automatic and manual callback options
  5. Enhanced error handling and logging

Usage

In Docker environment:

/CLIProxyAPI # ./CLIProxyAPI --login
# ... OAuth URL is displayed ...
# User opens URL in browser, authenticates, and gets redirected to localhost URL
# User copies the callback URL and pastes it in Docker terminal:
> http://localhost:8085/oauth2callback?code=4/0AY0e-g7r...&state=state-token
✓ Manual input received, processing...
✓ Authenticated user email: user@gmail.com

@gemini-code-assist
Copy link

Summary of Changes

Hello @zhizinan1997, 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 significantly improves the robustness of the Gemini OAuth2 authentication process, particularly for users operating in containerized (e.g., Docker) or remote environments. By implementing a manual callback input mechanism alongside the existing automatic flow, it ensures that users can successfully complete authentication even when network configurations prevent direct localhost callbacks, thereby enhancing usability and reliability.

Highlights

  • Manual Callback Support: Introduced the ability for users to manually input the OAuth2 callback URL or authorization code, specifically addressing issues in Docker and remote environments where automatic callbacks might fail.
  • Dual-Mode Listening: The authentication flow now simultaneously listens for both the traditional automatic HTTP callback and manual user input, with a 5-minute timeout.
  • Intelligent Code Extraction: A new helper function extractCodeFromInput() was added to robustly parse authorization codes from various formats, including full URLs, direct codes, and query strings.
  • Improved User Guidance: Enhanced user prompts provide clear instructions on how to proceed with authentication, including opening the URL in a browser and how to manually paste the callback information.
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

@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 introduces a valuable enhancement by adding support for manual OAuth2 callback input, which is very helpful for users in Docker or remote environments. The implementation is mostly solid, with clear instructions for the user.

I've found a critical issue in the new extractCodeFromInput function that would prevent valid authorization codes from being parsed correctly. I've also included a couple of medium-severity suggestions to improve logging and code clarity. Addressing these points will make the new feature more robust and maintainable.

}

// If input looks like a direct code (no spaces or special URL characters)
if !strings.Contains(input, " ") && !strings.Contains(input, "?") && !strings.Contains(input, "/") {

Choose a reason for hiding this comment

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

critical

This check for a direct authorization code is incorrect. It prevents codes containing a forward slash (/) from being processed. Google's authorization codes can and often do contain slashes (e.g., the example in the PR description 4/0AY0e-g7r...). This will cause the authentication to fail for users who paste such a code directly. The check for / should be removed.

Suggested change
if !strings.Contains(input, " ") && !strings.Contains(input, "?") && !strings.Contains(input, "/") {
if !strings.Contains(input, " ") && !strings.Contains(input, "?") {

go func() {
if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
log.Fatalf("ListenAndServe(): %v", err)
log.Debugf("ListenAndServe(): %v", err)

Choose a reason for hiding this comment

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

medium

Using log.Debugf here is too silent if server.ListenAndServe() fails for reasons other than a graceful shutdown (e.g., port already in use). This would prevent the automatic callback from ever working, forcing the user into the manual flow without a clear indication of what went wrong. It's better to use log.Warnf to make this failure more visible in the logs.

Suggested change
log.Debugf("ListenAndServe(): %v", err)
log.Warnf("ListenAndServe(): %v", err)

Comment on lines +381 to +389
// Try to parse as query string (code=... format)
if strings.HasPrefix(input, "code=") {
parts := strings.Split(input, "&")
for _, part := range parts {
if strings.HasPrefix(part, "code=") {
return strings.TrimPrefix(part, "code=")
}
}
}

Choose a reason for hiding this comment

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

medium

This block of code to handle inputs starting with code= is redundant. The subsequent block that checks for strings.Contains(input, "code=") is more general and correctly handles this case already. Removing this redundant block will simplify the function and improve maintainability.

@zhizinan1997
Copy link
Author

For the issue:
#295
Example(docker logs):
image

@luispater luispater changed the base branch from main to dev November 21, 2025 16:14
@luispater
Copy link
Collaborator

Didn't you modify main.go?

@zhizinan1997
Copy link
Author

Didn't you modify main.go?

I had not modified main.go or anyother file, look like works very well.

If possible, I suggest that after obtaining the login link on the web management panel, add an input field for the callback URL. This would be very user-friendly for those who are not good with command-line operations or who have complex network environments. You can refer to the management webpage of the gcli2api project for inspiration.

image

You can see a similar, very convenient implementation at the bottom of the gcli2api project’s web management page — the “Get credentials from the origin/return URL” feature in the screenshot.

@zhizinan1997
Copy link
Author

Didn't you modify main.go?

I had not modified main.go or anyother file, look like works very well.

If possible, I suggest that after obtaining the login link on the web management panel, add an input field for the callback URL. This would be very user-friendly for those who are not good with command-line operations or who have complex network environments. You can refer to the management webpage of the gcli2api project for inspiration.

image

You can see a similar, very convenient implementation at the bottom of the gcli2api project’s web management page — the “Get credentials from the origin/return URL” feature in the screenshot.

Actually, I ran into this issue myself because of a pretty complicated setup.
I’m in mainland China: my Windows PC is running Clash in TUN mode, and the Docker container on my domestic cloud server is using a Japanese HTTP/HTTPS proxy. In the end, the callback just couldn’t reach back successfully.
The main reason is probably that I’m not a professional programmer — I’m just an amateur/hobbyist, so my technical skills are limited. This kind of GUI option would really save people like me a lot of headache.
🤣🤣🤣

@luispater luispater closed this Dec 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants