Skip to content

Commit

Permalink
Check for multiple auth options (#105)
Browse files Browse the repository at this point in the history
`hasApiKey` checks whether an API or `HTTPClient` is provided, however
the check fails when using other auth options.

For example:

`client, err := genai.NewClient(ctx, option.WithTokenSource(ts))`

Results in the following error:
```
You need an API key to use this client.
Visit https://ai.google.dev to get one, put it in an environment variable like GEMINI_API_KEY,
then pass it as an option:
    genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GEMINI_API_KEY")))
(If you're doing that already, then maybe the environment variable is empty or unset.)
Import the option package as "google.golang.org/api/option".
```

This PR adds support for additional authentication options to address
this limitation.

fixes: #103 

---

Please let me know if you have any suggestions or require further
changes :)
  • Loading branch information
andersonjoseph authored May 9, 2024
1 parent e973ba7 commit 179b732
Showing 1 changed file with 13 additions and 10 deletions.
23 changes: 13 additions & 10 deletions genai/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ type Client struct {
// You may configure the client by passing in options from the [google.golang.org/api/option]
// package.
func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) {
if !hasAPIKey(opts) {
return nil, errors.New(`You need an API key to use this client.
Visit https://ai.google.dev to get one, put it in an environment variable like GEMINI_API_KEY,
if !hasAuthOption(opts) {
return nil, errors.New(`You need an auth option to use this client.
for an API Key: Visit https://ai.google.dev to get one, put it in an environment variable like GEMINI_API_KEY,
then pass it as an option:
genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GEMINI_API_KEY")))
(If you're doing that already, then maybe the environment variable is empty or unset.)
Expand All @@ -81,20 +81,23 @@ Import the option package as "google.golang.org/api/option".`)
return &Client{c, mc, fc, ds}, nil
}

// hasAPIKey reports whether the options imply that there is an API key.
// That is the case if either the WithAPIKey or WithHTTPClient options is present.
// (If the latter is present, we assume it handles auth).
// hasAuthOption reports whether an authentication-related option was provided.
//
// There is no good way to make these checks, because the types of the options
// are unexported, and the struct that they populates is in an internal package.
func hasAPIKey(opts []option.ClientOption) bool {
func hasAuthOption(opts []option.ClientOption) bool {
for _, opt := range opts {
v := reflect.ValueOf(opt)
ts := v.Type().String()
if ts == "option.withAPIKey" {

switch ts {
case "option.withAPIKEY":
return v.String() != ""
}
if ts == "option.withHTTPClient" {

case "option.withHttpClient",
"option.withTokenSource",
"option.withCredentialsFile",
"option.withCredentialsJSON":
return true
}
}
Expand Down

0 comments on commit 179b732

Please sign in to comment.