Add instance-managed OAuth providers - #339
Conversation
📝 Contributor License Agreement requiredBefore this PR can merge, every contributor must sign the Infisical CLA. Still needs to sign: Once everyone has signed, the check updates automatically — no need to close and reopen the PR. |
|
| Filename | Overview |
|---|---|
| internal/server/managed_oauth.go | New file wiring managed provider lookup into connect requests. applyManagedOAuthProvider does not reset req.DisablePKCE, letting callers weaken the PKCE requirement for managed flows. |
| internal/oauth/managed.go | New file loading managed OAuth provider config from env. Minor asymmetry: client ID is whitespace-trimmed but client secret is not. |
| internal/server/handle_oauth.go | Managed provider override applied before all existing validation; URL validation, secret handling, and token exchange logic unchanged and correct. |
| internal/server/handle_spa.go | Adds managed_oauth_providers list to the public /v1/status response; returns sorted IDs only, no secrets exposed. |
| internal/server/handle_credentials.go | enrichOAuthEntry now identifies managed providers by matching stored URLs and client ID; correctly avoids exposing client secret. |
| cmd/server.go | configureManagedOAuthProviders called in both server startup paths (direct and detached child) before serving requests. |
| web/src/pages/vault/CredentialsTab.tsx | UI correctly hides client ID/secret fields and shows an info banner for managed providers; client-side isManagedProvider check is cosmetic only — backend enforces the real provider values. |
| web/src/pages/vault/shared.tsx | useVaultParams now threads status.managed_oauth_providers from route context down to vault pages. |
| web/src/lib/oauthProviders.ts | Adds read-only and modify-level Google scopes for Calendar, Drive, Gmail, Docs, and Slides — straightforward expansion of the scope preset list. |
| internal/server/server.go | Adds managedOAuthProviders map field to Server struct; written once before startup, then only read concurrently — safe without a mutex. |
Reviews (1): Last reviewed commit: "feat: add managed OAuth providers" | Re-trigger Greptile
| req.AuthorizationURL = provider.AuthorizationURL | ||
| req.TokenURL = provider.TokenURL | ||
| req.ClientID = provider.ClientID | ||
| req.ClientSecret = provider.ClientSecret | ||
| req.TokenAuthMethod = provider.TokenAuthMethod | ||
| return nil |
There was a problem hiding this comment.
The
applyManagedOAuthProvider override leaves req.DisablePKCE untouched, meaning any API caller can send "disable_pkce": true and weaken the PKCE requirement for the managed Google flow. Since PKCE is a security control against authorization-code interception, its enablement should be dictated by the operator-defined provider config, not the caller.
| req.AuthorizationURL = provider.AuthorizationURL | |
| req.TokenURL = provider.TokenURL | |
| req.ClientID = provider.ClientID | |
| req.ClientSecret = provider.ClientSecret | |
| req.TokenAuthMethod = provider.TokenAuthMethod | |
| return nil | |
| req.AuthorizationURL = provider.AuthorizationURL | |
| req.TokenURL = provider.TokenURL | |
| req.ClientID = provider.ClientID | |
| req.ClientSecret = provider.ClientSecret | |
| req.TokenAuthMethod = provider.TokenAuthMethod | |
| req.DisablePKCE = false // managed providers always use PKCE | |
| return nil |
| googleClientID := strings.TrimSpace(os.Getenv(GoogleOAuthClientIDEnv)) | ||
| googleClientSecret := os.Getenv(GoogleOAuthClientSecretEnv) |
There was a problem hiding this comment.
googleClientID is whitespace-trimmed (to tolerate copy-paste errors) but googleClientSecret is not. An operator who accidentally copies the secret with a trailing newline or space will get a secret stored verbatim — causing token-exchange failures that are hard to diagnose. Trim both for consistency.
| googleClientID := strings.TrimSpace(os.Getenv(GoogleOAuthClientIDEnv)) | |
| googleClientSecret := os.Getenv(GoogleOAuthClientSecretEnv) | |
| googleClientID := strings.TrimSpace(os.Getenv(GoogleOAuthClientIDEnv)) | |
| googleClientSecret := strings.TrimSpace(os.Getenv(GoogleOAuthClientSecretEnv)) |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Agent Vault currently requires every vault user to create and enter a separate OAuth application, even when one deployment wants to offer the same provider to everyone.
This adds operator-managed OAuth providers, starting with Google. The server owns the application credentials and provider endpoints, while each vault receives its own separately encrypted access and refresh tokens. The UI exposes configured providers without revealing the shared client secret, and custom per-vault providers remain available.
Validation: