-
Notifications
You must be signed in to change notification settings - Fork 5
feat: aibrige BYOK #216
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
base: main
Are you sure you want to change the base?
feat: aibrige BYOK #216
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -110,11 +110,31 @@ func (p *Anthropic) CreateInterceptor(w http.ResponseWriter, r *http.Request, tr | |
| cfg := p.cfg | ||
| cfg.ExtraHeaders = extractAnthropicHeaders(r) | ||
|
|
||
| // In centralized mode, http.go strips Authorization and X-Api-Key | ||
| // (they carried the Coder token), so neither header is present | ||
| // here and cfg keeps the centralized key. | ||
| // | ||
| // In BYOK mode, http.go only strips the BYOK header and leaves | ||
| // the user's LLM credentials intact: | ||
| // - Authorization: Bearer <oauth-token> → subscription (Claude | ||
| // Max/Pro). Set BYOKBearerToken so the SDK uses | ||
| // WithAuthToken(), and clear the centralized key. | ||
| // - X-Api-Key: <api-key> → personal API key. Overwrite the | ||
| // centralized key with the user's key. | ||
| authHeaderName := p.AuthHeader() | ||
| if bearer := r.Header.Get("Authorization"); bearer != "" { | ||
| cfg.BYOKBearerToken = strings.TrimPrefix(bearer, "Bearer ") | ||
| cfg.Key = "" | ||
| authHeaderName = "Authorization" | ||
| } else if apiKey := r.Header.Get("X-Api-Key"); apiKey != "" { | ||
| cfg.Key = apiKey | ||
| } | ||
|
Comment on lines
+129
to
+131
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From this point on, we no longer know whether this interception is using a centralized (global) key or a BYOK (user's personal) API key, right? This could be useful to store and to show in the logs (the same for BYOK oauth token). For example, if Anthropic returns a 401, we wouldn't know if the failing key is the global key (affecting everyone) or a single user's personal key. Additionally, this is probably out of scope for this PR, but it might make sense to store this information in the interception so we can later surface it in the UI, wdyt? |
||
|
|
||
| var interceptor intercept.Interceptor | ||
| if req.Stream { | ||
| interceptor = messages.NewStreamingInterceptor(id, &req, payload, cfg, p.bedrockCfg, r.Header, p.AuthHeader(), tracer) | ||
| interceptor = messages.NewStreamingInterceptor(id, &req, payload, cfg, p.bedrockCfg, r.Header, authHeaderName, tracer) | ||
| } else { | ||
| interceptor = messages.NewBlockingInterceptor(id, &req, payload, cfg, p.bedrockCfg, r.Header, p.AuthHeader(), tracer) | ||
| interceptor = messages.NewBlockingInterceptor(id, &req, payload, cfg, p.bedrockCfg, r.Header, authHeaderName, tracer) | ||
| } | ||
| span.SetAttributes(interceptor.TraceAttributes(r)...) | ||
| return interceptor, nil | ||
|
|
@@ -137,6 +157,12 @@ func (p *Anthropic) InjectAuthHeader(headers *http.Header) { | |
| headers = &http.Header{} | ||
| } | ||
|
|
||
| // BYOK: if the request already carries user-supplied credentials, | ||
| // do not overwrite them with the centralized key. | ||
| if headers.Get("X-Api-Key") != "" || headers.Get("Authorization") != "" { | ||
| return | ||
| } | ||
|
|
||
| headers.Set(p.AuthHeader(), p.cfg.Key) | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package utils | ||
|
|
||
| // MaskSecret returns the first 4 and last 4 characters of s | ||
| // separated by "...", or the full string if 8 characters or fewer. | ||
| func MaskSecret(s string) string { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a good idea? I think logging the auth mode ("centralized", "byok_bearer", "byok_apikey") rather than a hint of the secret might be cleaner 👀 |
||
| if len(s) <= 8 { | ||
| return s | ||
| } | ||
| return s[:4] + "..." + s[len(s)-4:] | ||
| } | ||
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'm confused by this comment, is this a reference to the coder repo? If yes, I would suggest not using
http.goand making it clear that the upstream caller needs to stripAuthorizationandX-API-Keyheaders.IIUC, at this point, the headers are as follows: