Skip to content

feat(auth): support OAuth 2.0 client credentials - #135

Open
galpgustavoflor wants to merge 1 commit into
collibra:mainfrom
galpgustavoflor:feat/oauth-client-credentials
Open

feat(auth): support OAuth 2.0 client credentials#135
galpgustavoflor wants to merge 1 commit into
collibra:mainfrom
galpgustavoflor:feat/oauth-client-credentials

Conversation

@galpgustavoflor

Copy link
Copy Markdown

Description of your changes

Adds a third authentication mode: OAuth 2.0 client credentials.

Organisations whose Collibra instance is fronted by SSO (SAML/OIDC) have no local password for federated users, so both existing modes (server-wide Basic credentials and client-supplied Authorization headers) fail with authenticationFailed. Collibra issues Bearer tokens through the client_credentials grant at /rest/oauth/v2/token; this change lets chip use them.

When api.oauth.client-id and api.oauth.client-secret are set (env: COLLIBRA_MCP_API_OAUTH_CLIENT_ID / COLLIBRA_MCP_API_OAUTH_CLIENT_SECRET, flags: --api-oauth-client-id / --api-oauth-client-secret), chip:

  • obtains a token from the Collibra token endpoint, sending the client credentials as HTTP Basic as Collibra expects;
  • caches it and refreshes it before expiry (via clientcredentials.Config.TokenSource, which already returns a ReuseTokenSource);
  • sends Authorization: Bearer <token> on every outgoing Collibra API request, in both stdio and HTTP modes;
  • routes the token request through the same base transport, so api.proxy and api.skip-tls-verify apply to it as well.

The token endpoint defaults to <api.url>/rest/oauth/v2/token and can be overridden with api.oauth.token-url.

Precedence in RoundTrip is OAuth, then server-wide Basic, then the client-supplied header; the two existing branches keep their order and behaviour.

Startup validation fails with a message when only one of client-id/client-secret is set, when OAuth and username/password are both set, or when the token URL is not absolute. Token endpoint response bodies are stripped from returned errors so neither the client secret nor a token can reach logs or tool results. A warning is logged that all actions are attributed to the OAuth client's account, mirroring the existing Basic-auth warning.

Files: cmd/chip/config.go, cmd/chip/http.go, cmd/chip/main.go, new cmd/chip/http_test.go, go.mod, README.md, docs/CONFIG.md, docs/mcp.yaml.example. The two Go files already touched were also run through gofmt, which realigned two struct literals that were previously misaligned.

Tests (cmd/chip/http_test.go, table-driven with httptest) cover: Bearer header sent and token endpoint called once across two requests; Basic auth with no token call; client header pass-through; token endpoint 401 returns an error that does not contain the secret and no request reaches the API; token URL derivation with and without trailing slash, with a path prefix, and with an explicit override; and the config validation rules.

Manual verification against a real instance: register a client with POST /rest/auth/v1/clients and body {"client_name": "mcp-chip", "grant_types": ["client_credentials"]} (the secret is returned once), confirm curl -u "<client_id>:<client_secret>" -d grant_type=client_credentials https://<instance>/rest/oauth/v2/token returns a token, then run chip with the two env vars and call list_asset_types.


Impact Analysis

  • The change is additive. With no OAuth configuration, RoundTrip follows the same two branches as before and existing tests pass untouched.
  • golang.org/x/oauth2 moves from the indirect to the direct require block (via go mod tidy); no new module enters the dependency graph and go.sum is unchanged.
  • No changes to tools, pkg/clients, or the tool registry.
  • Not a breaking change. Misconfiguration now fails at startup rather than at the first tool call, which only affects configurations that were already invalid (OAuth fields did not exist before).
  • Quality gates run locally with Go 1.25.0: go build -v ./..., go test -race ./..., golangci-lint run (v2.4.0), gofmt -l on the changed files. The only test failures on this Windows machine are four pre-existing path-handling tests in pkg/skills that fail identically on main and are unrelated.

Checklist

  • I have performed a self-review of my code
  • My code follows the contribution guidelines of this project
  • My changes generate no new warnings

🤖 Generated with Claude Code

Organisations whose Collibra instance is fronted by SSO (SAML/OIDC) have
no local password for federated users, so both existing authentication
modes (server-wide Basic credentials and client-supplied Authorization
headers) fail with "Failed to authenticate request through basic
credentials". Collibra itself issues Bearer tokens through the OAuth 2.0
client credentials grant at /rest/oauth/v2/token, but chip had no way to
use them.

Add a third authentication mode. When api.oauth.client-id and
api.oauth.client-secret are configured, chip obtains a token from the
Collibra token endpoint (credentials sent as HTTP Basic, as Collibra
expects), caches it, refreshes it before expiry, and sends
"Authorization: Bearer <token>" on every outgoing Collibra API request.
The token request reuses the base transport so proxy and TLS settings
apply to it as well. OAuth takes precedence over Basic auth; the two
existing branches keep their order and behaviour, and with no OAuth
configuration the code path is unchanged.

Misconfiguration (only one of id/secret, OAuth combined with
username/password, or a non-absolute token URL) fails at startup with
an actionable message. Token endpoint response bodies are stripped from
errors so neither the client secret nor a token can reach logs or tool
results.

No new dependency is added: golang.org/x/oauth2 was already an indirect
requirement and is promoted to a direct one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@galpgustavoflor
galpgustavoflor requested a review from a team as a code owner September 8, 2026 00:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant