feat(wasm): per-request credentials from session variables#604
Open
codybrom wants to merge 4 commits into
Open
feat(wasm): per-request credentials from session variables#604codybrom wants to merge 4 commits into
codybrom wants to merge 4 commits into
Conversation
…dentials Adds `auth_token_setting` and `auth_token_prefix` server options to the OpenAPI FDW, allowing a Postgres session configuration variable to supply the authentication credential at query time rather than at server creation. The credential is resolved via `current_setting(name, true)` each time a request is made, so a security-definer wrapper function can inject a per-user or per-transaction token via `set_config(..., true)` before querying the foreign table. An empty or absent setting is a no-op, preserving any static credential configured at server level. Implementation: - Add `query-setting` to the utils WIT interface (v1 + v2) - Implement `query_setting()` in supabase-wrappers via SPI - Wire host binding in wasm_fdw/host/utils.rs (v1 + v2) - Add `auth_token_setting` / `auth_token_prefix` fields to ServerConfig - Extract `apply_session_token()` as a pure testable helper - Apply override in `make_request` before each HTTP call - Add 15 unit tests covering all override edge cases
Adds a pgrx integration test exercising the auth_token_setting path end-to-end: with a session GUC unset the FDW injects no Authorization header, and after set_config(...) the resolved token is sent prefixed. This is the only runtime coverage of the query-setting host function -> SPI -> guest round-trip; the existing unit tests only cover the pure apply_session_token helper in isolation. - wasm_fdw/tests.rs: new #[pg_test] openapi_session_token_injection (negative + positive cases) against the local mock on :8096 - dockerfiles/wasm/server.py: add /whoami route that reflects the received Authorization header so the test can assert on it
Contributor
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR adds support for injecting per-session auth tokens into OpenAPI FDW requests by resolving a Postgres session GUC via a new WASM host utility, and validates the behavior end-to-end with a mock server and tests.
Changes:
- Added
query-settingto the WASM utils WIT interface and host implementation. - Implemented dynamic Authorization header injection in
openapi_fdwdriven byauth_token_setting/auth_token_prefix. - Added integration + unit tests and updated the mock server to reflect the received
Authorizationheader.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| wrappers/src/fdw/wasm_fdw/tests.rs | Adds an end-to-end test validating session-token injection behavior. |
| wrappers/src/fdw/wasm_fdw/host/utils.rs | Exposes query_setting as a WASM host function for both utils interface versions. |
| wrappers/dockerfiles/wasm/server.py | Adds a /whoami endpoint to echo back the Authorization header for tests. |
| wasm-wrappers/wit/v1/utils.wit | Extends utils interface with query-setting. |
| wasm-wrappers/wit/v2/utils.wit | Extends utils interface with query-setting. |
| wasm-wrappers/fdw/openapi_fdw/src/request.rs | Injects a session-resolved Authorization header at request time. |
| wasm-wrappers/fdw/openapi_fdw/src/config_tests.rs | Adds unit tests for session-token header injection logic. |
| wasm-wrappers/fdw/openapi_fdw/src/config.rs | Adds auth token config fields and apply_session_token helper. |
| supabase-wrappers/src/utils.rs | Adds query_setting() helper using current_setting(name, true). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- apply_session_token: match the authorization header case-insensitively so a static Authorization header (e.g. from the headers option) is replaced rather than duplicated - query_setting: report unexpected SPI errors instead of swallowing them, matching get_vault_secret (still returns None; absent settings are not errors thanks to current_setting(name, true)) - configure_auth: treat an empty/whitespace auth_token_setting as unset to avoid a pointless per-request lookup, and trim auth_token_prefix - tests: rename the prefix-default test to reflect the empty struct default, add a case-insensitive replace regression test
Contributor
Author
|
Addressed all four Copilot review comments in
|
- openapi.md: auth_token_setting / auth_token_prefix server options, updated authentication limitation, and a per-request credentials example - wasm-advanced.md: new Host functions section documenting the utils interface, including query_setting for reading session GUCs - openapi_fdw README: note per-request session-variable tokens
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.
What kind of change does this PR introduce?
Feature. Adds a generic host function for reading a Postgres session variable at request time, plus an OpenAPI FDW option that uses it as the auth credential.
My use case is per-user access in a multi-tenant app. Each user has their own upstream token to a third-party system (OAuth access tokens, per-user API keys) and with Supabase Auth those tokens live in a per-user, RLS-protected table keyed to
auth.uid(). My approach is aSECURITY DEFINERfunction that reads the calling user's token and pins it for the life of the query. This lines up with how Supabase already threads per-user context into Postgres. Theauth.uid()comes from a session GUC (request.jwt.claims) so resolving a credential from a session variable is the same shape and not a new concept.What is the current behavior?
A wasm FDW can only authenticate with a static credential that's fixed when the server is created, either inline in the server options or a Vault secret looked up by id/name. There's no way to hand it a credential that changes per request, per user, or per transaction.
What is the new behavior?
With this PR, stored Supabase Auth credentials can be resolved from a Postgres session variable on each request, so it can match per user/request/transaction. Implemented with two main pieces that are purely additive and backward compatible so an absent or empty setting is a no-op and any static credential configured at the server level still applies.
query-setting(name)added to the utils WIT interface (v1 + v2), backed bycurrent_setting(name, true)via SPI. Returns None when the setting is unset.auth_token_setting/auth_token_prefixserver options on the OpenAPI FDW. Whenauth_token_settingis set, the FDW reads that session variable per request and uses it as the Authorization token.Design note
As shipped, the query-setting function could read any Postgres session setting, not just an auth token, but the auth option is the only setting being read. I could have made it smaller and more focused as auth-only, but I went general because it's a simple tool other FDWs could reuse and other session settings aren't typically sensitive. Could be tightened to read auth only if preferred.
Additional context
Alternatives considered
WHERE token = ...), handled entirely in the guestTesting
apply_session_tokencovering the edge cases (empty/whitespace no-op, custom prefix, replacing vs appending the header, overriding a static credential).openapi_session_token_injection) that runs the full path against the mock server: with the GUC unset no Authorization header is sent, and after set_config the token arrives prefixed.