Skip to content

Support OAuth authentication in HTTP transport #150

@AviatorJLat

Description

@AviatorJLat

Summary

Add OAuth bearer token authentication as an alternative to keypair JWT in the HTTP transport. This would enable browser-based OAuth (authorization code flow) for local development, where managing RSA keypairs per
developer is friction that discourages adoption.

Motivation

Our team uses Snowflake as a data warehouse and Snowflex as our Ecto adapter. In production, keypair JWT works well. But for local development, requiring each developer to generate an RSA keypair, register the
public key fingerprint in Snowflake, and manage key files adds significant onboarding overhead.

Snowflake's SQL REST API already supports OAuth bearer tokens via the X-Snowflake-Authorization-Token-Type: OAUTH header. Supporting this in Snowflex would let teams use browser-based SSO (which most orgs already
have configured) for dev environments while keeping keypair auth for production.

This isn't just our use case — Snowflake's own documentation recommends OAuth for interactive/user-facing authentication and keypair for service accounts, which maps cleanly to dev vs. production.

Proposed approach

The HTTP transport already has a clean separation between auth and query execution. The change could be scoped to:

  1. Add an :auth_method option to Snowflex.Transport.Http (:keypair default, :oauth)
  2. When :oauth, skip keypair validation and read a bearer token from a configurable source (e.g., :token option, or a {module, function, args} callback for refresh)
  3. Set the correct headerX-Snowflake-Authorization-Token-Type: OAUTH instead of KEYPAIR_JWT
  4. Token refresh callback — OAuth tokens expire; a callback lets users handle refresh without Snowflex owning the OAuth flow itself

The token acquisition (browser flow, mix task, etc.) would be left to the consuming application — Snowflex would only need to accept and use the token.

Example configuration

# Dev — OAuth with a token provider callback
config :my_app, MyApp.SnowflakeRepo,
  adapter: Snowflex,
  transport: Snowflex.Transport.Http,
  auth_method: :oauth,
  token: {MyApp.Snowflake.TokenProvider, :get_token, []},
  account_name: "my-org-my-account",
  database: "MY_DB",
  schema: "MY_SCHEMA",
  warehouse: "MY_WH"

# Production — keypair (unchanged, existing behavior)
config :my_app, MyApp.SnowflakeRepo,
  adapter: Snowflex,
  transport: Snowflex.Transport.Http,
  account_name: "my-org-my-account",
  username: "service_account",
  private_key_path: "/path/to/key.pem",
  public_key_fingerprint: "SHA256:..."

Scope

  • OAuth token usage in the HTTP transport (small change)
  • Token acquisition/refresh is the consumer's responsibility (Snowflex doesn't own the OAuth flow)
  • No changes to the Ecto adapter layer, query generation, or existing keypair behavior

Willingness to contribute

I'm happy to implement this and open a PR if the approach sounds reasonable. Would appreciate feedback on the interface design before starting — particularly whether a {m, f, a} callback vs. a simple :token string is preferred for the token source.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions