Skip to content

[PureGo] Add custom auth-header hook to transport#494

Open
zlata-stefanovic-db wants to merge 6 commits into
mainfrom
purego-transport-headers
Open

[PureGo] Add custom auth-header hook to transport#494
zlata-stefanovic-db wants to merge 6 commits into
mainfrom
purego-transport-headers

Conversation

@zlata-stefanovic-db

@zlata-stefanovic-db zlata-stefanovic-db commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

First of a 3-PR stack splitting the original purego OAuth branch. Base of the stack — targets main.

Adds HeadersProvider-based auth to the ephemeral stream transport layer as the single source of stream credentials:

  • StreamParams carries an optional HeadersProvider. When set, GetHeaders supplies the auth (and any other) metadata headers; when nil, the stream is opened without an auth header.
  • withStreamMetadataHeaders merges provider headers into stream metadata; the table-name header stays authoritative from stream-open params.
  • Non-ASCII / control chars in header values are rejected at the wire boundary, so gRPC fails loudly rather than opaquely.
  • An auth rejection (Unauthenticated/PermissionDenied) on open invalidates the provider so the next open re-mints.
  • GetHeaders runs under the open deadline (the caller's ctx, defaulted to defaultHandshakeTimeout when it has none), so a blocking token mint can't hang Open indefinitely.

No dependency on the auth package — transport declares its own local HeadersProvider interface and consumes it duck-typed.

There is no StreamParams.Token: the raw-token field was dropped in favor of the provider hook, matching the auth model used by the other SDKs. Token normalization (bare token → "Bearer <token>", known schemes — Bearer/Basic/DPoP — sent verbatim) still happens in transport when it sets the authorization header.

Stack

  1. this PR — transport header hook
  2. [PureGo] Add auth provider interfaces and per-table token cache #495 — auth HeadersProvider + token cache
  3. [PureGo] Add UC OAuth token provider with per-table caching #496 — UC OAuth provider

Test plan

  • go build ./... and go test ./internal/transport/ pass.

@zlata-stefanovic-db zlata-stefanovic-db force-pushed the purego-transport-headers branch from 9a37c80 to dd85ce6 Compare July 13, 2026 09:53
@zlata-stefanovic-db zlata-stefanovic-db self-assigned this Jul 13, 2026
@zlata-stefanovic-db zlata-stefanovic-db force-pushed the purego-transport-headers branch from dd85ce6 to 9bd111b Compare July 13, 2026 10:01
@zlata-stefanovic-db zlata-stefanovic-db marked this pull request as ready for review July 13, 2026 10:10
@zlata-stefanovic-db zlata-stefanovic-db requested a review from a team July 13, 2026 10:10
@zlata-stefanovic-db zlata-stefanovic-db marked this pull request as draft July 13, 2026 10:27
@zlata-stefanovic-db zlata-stefanovic-db force-pushed the purego-transport-headers branch 2 times, most recently from ac84862 to a8ccc95 Compare July 13, 2026 10:33
@zlata-stefanovic-db zlata-stefanovic-db marked this pull request as ready for review July 13, 2026 10:39
Add HeadersProvider support to the ephemeral stream: StreamParams gains an
optional HeadersProvider used in place of Token, withStreamMetadataHeaders
merges provider headers (table name stays authoritative from stream-open
params), and an auth rejection on open invalidates the provider. Reject
non-ASCII/control chars at the wire boundary for every token source.

When a HeadersProvider is set, Token is ignored per its documented contract:
Open passes an empty token so a provider that omits an authorization header
cannot silently fall back to sending Token.

Signed-off-by: Zlata Stefanovic <zlata.stefanovic@databricks.com>
Add control-char rejection tests for provider header values and document
that GetHeaders runs before the handshake timeout is applied.

Signed-off-by: Zlata Stefanovic <zlata.stefanovic@databricks.com>
Broaden isUsableAsHeader godoc to cover all metadata values and
parameterize auth-rejection invalidation tests for PermissionDenied.

Signed-off-by: Zlata Stefanovic <zlata.stefanovic@databricks.com>
@zlata-stefanovic-db zlata-stefanovic-db force-pushed the purego-transport-headers branch from cf75cbf to b22dc27 Compare July 13, 2026 15:51
Comment thread purego/internal/transport/ephemeral_stream.go Outdated
Comment thread purego/internal/transport/ephemeral_stream.go Outdated
return nil, fmt.Errorf("transport: open %q: header %q contains invalid value characters", p.TableName, strings.TrimSpace(k))
}
}
} else if !isUsableAsHeader(p.Token) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might have this planned out already, but if HeadersProvider is not set, I think we should ideally default to OAuth currently and the other mandatory header(s).

@zlata-stefanovic-db zlata-stefanovic-db Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will land in one of the stacked PRs (#496), but noted.

Comment thread purego/internal/transport/metadata.go Outdated
Comment thread purego/internal/transport/ephemeral_stream.go Outdated
// authHeaderValue normalizes a token into an authorization header value: a value
// already carrying a known scheme (Bearer/Basic/DPoP) is returned verbatim, a
// bare token is prefixed with "Bearer ", and an empty token yields "".
func authHeaderValue(token string) string {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Predates this PR but are we sure it is okay for the authorization header to not start with anything other than "Bearer..."?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not introduced here, Rust core & other SDKs always format it as "Bearer "

Signed-off-by: Zlata Stefanovic <zlata.stefanovic@databricks.com>
Signed-off-by: Zlata Stefanovic <zlata.stefanovic@databricks.com>
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.

2 participants