-
Notifications
You must be signed in to change notification settings - Fork 427
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: adding oauth for gemini #1007
Conversation
ab23c56
to
35f64b6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
Comments suppressed due to low confidence (1)
crates/goose/src/providers/oauth.rs:345
- The DEFAULT_REDIRECT_URL is hardcoded in the get_oauth_token_with_endpoints_async function. It should be passed as a parameter.
DEFAULT_REDIRECT_URL.to_string(),
196fafc
to
cb6f005
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
crates/goose/src/providers/oauth.rs:325
- [nitpick] The
get_oauth_token_with_endpoints_async
function duplicates logic fromget_oauth_token_async
. Refactor to avoid code duplication.
pub async fn get_oauth_token_with_endpoints_async(
cb6f005
to
759deab
Compare
759deab
to
8adfbcd
Compare
the CLI is working for me but the behaviour is surprising. i did not see the OAuth consent screen. i did double check that GOOGLE_API_KEY wasn't set in env var or the keyring so i am not sure how it was still working. is that expected? the frontend currently requires the API Key though:
|
That is a good point about the GUI. I definitely was getting the oauth screen with Googe with the credential I made. Then are then cached in |
that'd be helpful. the oauth directory doesn't exist for me but very possible its cached somewhere else
|
c288b41
to
7516cdf
Compare
Improved the error message
And in the generated log file it gives the path, and how long it will be valid.
This leaves goose configure to prompt for an API key. No sure on the best path for the configure and front end since there are now two options for one provider. |
@@ -136,6 +241,8 @@ impl Provider for GoogleProvider { | |||
vec![ | |||
ConfigKey::new("GOOGLE_API_KEY", true, true, None), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently via environment variable, some design choices need to be made for how configure/UI work if a Provider has more than one option. So while that is determined left configure and UI to only use the API token.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How have you been testing this?
I tried
- forcing the oauth configuration and providing valid client id, client secret values -> was able to use gemini in a session
- forcing the oauth configuration and providing invalid client id, client secret values -> was able to use gemini in a session
- using the api key and providing invalid api key value -> was able to use gemini in a session
![image](https://private-user-images.githubusercontent.com/7952060/409230201-aa5b9cd9-624a-47c5-bc0b-21e4b0ae00fa.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxNzM3MTYsIm5iZiI6MTczOTE3MzQxNiwicGF0aCI6Ii83OTUyMDYwLzQwOTIzMDIwMS1hYTViOWNkOS02MjRhLTQ3YzUtYmMwYi0yMWU0YjBhZTAwZmEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxMCUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTBUMDc0MzM2WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZjNiMjZhMDU1ZGI2NjE4ZWYxMGMwNjU1YTM1OTIwMzM4ZjdkY2FjMTU4NjU1YjM5OTg1M2JiYWJiZGIzNWVjNiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.uMJo1s0cG09er_juwTbbuIivyjbO1PznO_52DHKnXus)
so it seems a little strange to me that gemini is usable despite providing invalid credentials
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not mean to approve
|
||
async fn ensure_auth_header(&self) -> Result<String, ProviderError> { | ||
match &self.auth { | ||
GoogleAuth::ApiKey(key) => Ok(format!("Bearer {}", key)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to format this into a Bearer {}
type token if it is only used in the url params key={api_key}
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can give that a try, went through a few iterations before I got it working.
|
||
fs::create_dir_all(get_base_path()).unwrap(); | ||
let cache_path = get_base_path().join(format!("{}.json", hash)); | ||
let base_path = dirs::config_dir() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need to do some consolidation around our config dir setup (which is out of scope of this PR), but we actually use ~/.config
even on macos
dirs::config_dir()
would drop us in $HOME/Library/Application Support
we should stick with the hard coded ~/.config` directory within this pr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, can put it in ~/.config
let cache_path = get_base_path().join(format!("{}.json", hash)); | ||
let base_path = dirs::config_dir() | ||
.unwrap_or_else(|| PathBuf::from(".")) | ||
.join("goose/google/oauth"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this would drop databricks
oauth tokens in to the google
directory, we'll need to change that to either be generic or pass in some other named parameter to distinguish where any specific oauth implementation will go
let flow = OAuthFlow::new( | ||
endpoints, | ||
client_id.to_string(), | ||
client_id.to_string(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this would break any flows using fn get_oauth_token_async
?, which i believe breaks the databricks
provider. it would just pass in client_id twice, one as the client_secret even if not needed.
also for any callers of this, if it's a public client it wouldn't need the client_secret
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, not sure. I will see about splitting this out.
@@ -60,6 +60,7 @@ serde_yaml = "0.9.34" | |||
once_cell = "1.20.2" | |||
dirs = "6.0.0" | |||
rand = "0.8.5" | |||
oauth2 = { version = "4.4", features = ["reqwest"] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not super familiar with this library, we use https://crates.io/crates/yup-oauth2 in the goose-mcp
crate, do you know what distinctions there are?
some larger questions around the oauth flow:
- whats the expected duration of the token?
- if short-lived will the changes automatically re-attempt an oauth flow if tokens are expired?
- does/should this
oauth2
crate and implementation handle refresh tokens?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can see if it will also work with yup-oauth2, if that is already an existing library.
As to the flow, the token lasts an hour I believe. If the token is expired it will get a new token. Does the databrick token also expire?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks to be about the same for databricks
, about an hour and then we do the same oauth local browser flow
Yeah we use yup-oauth2
but in a slightly different context, for google's Desktop client OAuth flow, but hopefully it does work
Co-authored-by: Kalvin C <kalvinnchau@users.noreply.github.com>
This enables use of Gemini with either an API token, and oauth by setting
GOOGLE_CLIENT_ID
andGOOGLE_CLIENT_SECRET