feat: per-provider user_provided API key UI + real expiry on chat sends (#70)#81
Merged
Merged
Conversation
Contributor
Android debug APKArtifact:
|
garfiec
added a commit
that referenced
this pull request
May 10, 2026
garfiec
added a commit
that referenced
this pull request
May 10, 2026
garfiec
added a commit
that referenced
this pull request
May 10, 2026
865d2ad to
174426c
Compare
Adds a Provider API Keys screen under Settings → Security and a "Set API Key" CTA on greyed endpoint groups in the chat model selector for endpoints configured with userProvide / userProvideURL. Mirrors the LibreChat web UX so mobile-only users can unblock user-provided endpoints without the web app. - core/model: promote KeyState to shared domain; add KeyInvalidation and ProviderKeyName helpers; ExpiredUserKey.endpoint is nullable - core/data: KeyRepository emits invalidation events (replay=0, DROP_OLDEST) for cross-screen refresh after set/revoke - feature/settings: ProviderKeysScreen + SetProviderKeyDialog with cancel-and-restart refresh and merge-on-cancel so the just-mutated row survives a concurrent endpointConfigs emission - feature/chat: EndpointKeyStatusDelegate fans out per-endpoint key state, ModelSelectorSheet renders greyed groups with a Set API Key chip, and UserKeyError snackbars deep-link to the dialog - shared/navigation: Navigator.navigateToProviderKeys(endpointName) with top-of-stack dedup
174426c to
231d21e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #70.
Summary
user_providedserver can now configure and revoke per-endpoint keys without the web client — unblocks the smoking-gun scenarios behind Incorrect passing of API tokens #60.key: "never"literal inEndpointClassifierwith the real per-endpoint expiry fromgetKeyExpiry. The backend'scheckUserKeyExpiryguard now sees the truth instead of a silent-passInvalid Date.no_user_key/expired_user_keySSE errors to a snackbar that deep-links into the Set API Key dialog for the offending endpoint, instead of a generic SSE failure.KeysApibugs called out in Per-provider user_provided API key UI + send real expiry on chat sends #70 (wronggetKeyExpirysignature, fictionalUserKey.value,updateKeytyped against a non-existent response body).What changed
KeyStatedomain type and aKeyInvalidationSharedFlow onKeyRepository— single source of truth for per-endpoint key state, with cross-screen refresh when a set/revoke happens elsewhere.EndpointClassifiernow takes the resolved expiry and writes the real ISO string (or"never"only when the user genuinely has a non-expiring key) onto the chat-send body.Unset/Expiredas greyed with a primary-tinted "⚙ Set API Key" chip. Tapping the chip deep-links straight into the dialog for that endpoint. Comparison-mode sheet uses the same presentation. Transient fetch errors (e.g. a 401 mid-auth-refresh) preserve the previously-resolved row state instead of flashing every endpoint to greyed.Navigator.navigateToProviderKeys(endpointName)with top-of-stack dedup so rapid double-taps don't push duplicate entries.SetKeyDialog: Azure (4-field quad → nested JSON envelope), OpenAI / Assistants (apiKey + rendered-but-optionalbaseURLwhenuserProvideURL=true, matching the upstreamisOpenAIBaseskip), Custom (<name> API Key/<name> API URLinterpolated labels, baseURL required whenuserProvideURL=true), Google (paste-or-import service-account JSON with client-sideclient_email/project_id/private_keyvalidation + optional Gemini API key, marshalled as{ GOOGLE_SERVICE_KEY, GOOGLE_API_KEY }), Bedrock (structured{ accessKeyId, secretAccessKey, sessionToken? }— deliberately diverges from web'sOtherConfigfallthrough; documented in code), and the single-input fallback for everything else.azureAssistantsintentionally routes to the plain OpenAI form to mirror upstream'sSetKeyDialog.tsx:215behavior (documented inline).ProviderKeysViewModel, navigation dedup, andKeysApireal-wire decoding. The Set Key dialog has 40 unit tests covering every form variant's wire envelope, validation rules, expiry handling, file picker, and revoke flow.Screenshots
Captured on Pixel_10_Pro_Fold AVD against a server with an OpenRouter (
userProvide) endpoint and no key set. Tapping the "Set API Key" chip in the model selector deep-links directly into the Set Key dialog over the Provider Keys screen.