2.6 KiB
HTTP Client
Use go.gearno.de/kit/httpclient for every outbound HTTP call. Never use http.DefaultClient or a bare &http.Client{}.
SSRF protection is the default
Every call goes through httpclient.DefaultClient(...) / httpclient.DefaultPooledClient(...) / httpclient.DefaultPooledTransport(...) with httpclient.WithSSRFProtection() enabled. This applies whenever the destination URL is:
- Customer-supplied (webhook endpoint, OAuth2 token URL, SCIM bridge URL, connector-provided base URL)
- Reached through a customer-supplied connector (OAuth2/APIKey connection clients)
- A hardcoded third-party provider host (Slack, Linear, GitHub, Google Workspace, Sentry, …) — defense in depth, and public IPs pass the check unchanged
client := httpclient.DefaultPooledClient(
httpclient.WithLogger(logger),
httpclient.WithSSRFProtection(),
)
What the option does:
- Rejects dials to loopback, RFC 1918 private, RFC 6598 CGNAT, link-local, multicast, unspecified, ULA, IPv4-mapped IPv6, and IETF-reserved ranges. Check runs on the resolved peer IP at connect time, defeating DNS rebinding.
- On
DefaultClient/DefaultPooledClient, also refuses redirects whose scheme, host, or port differs from the original.
When to omit SSRF protection
Only when the target is an internal service you actively intend to reach (sandbox-local service, sidecar, in-cluster endpoint with a known private IP). These cases are rare in this codebase — confirm the intent in code review. Do not disable it "just to make a test pass."
For tests that need to hit an httptest server on loopback, add httpclient.WithSSRFAllowLoopback() on top of WithSSRFProtection() (or inject a loopback-friendly client into the component under test). Production callers must not use the loopback exemption.
Connector wiring
OAuth2Connector.HTTPClient is a required field for the token-exchange request. Set it via connector.ApplyProviderDefaults, which wires an SSRF-protected client. Don't re-introduce a nil fallback in CompleteWithState — callers must provide the client explicitly.
OAuth2Connection.ClientWithOptions, RefreshableClient, clientCredentialsClient and APIKeyConnection.Client already append WithSSRFProtection() internally; additional caller options layer on top.
Summary
- Customer-reachable URL →
WithSSRFProtection(), always. - Third-party SaaS →
WithSSRFProtection(), always (public IPs pass). - Local/internal service you meant to dial → document why and omit.
- Test against
httptest→WithSSRFProtection()+WithSSRFAllowLoopback().