OAuth And Token Sources

Copy Markdown View Source

Pristine.OAuth2 is the runtime OAuth control plane. It handles authorization URL generation, token exchange, token refresh, and token persistence over the runtime transport boundary.

Ownership split:

  • pristine owns the generic OAuth runtime mechanics
  • provider SDK repos own provider URLs, scopes, and provider-local helper modules
  • higher control planes own durable install records, secret authority, and hosted callback routes

Env-backed OAuth client ids, client secrets, and saved token files are standalone compatibility inputs. When a runtime context has governed_authority, Pristine rejects OAuth token requests and saved-token refresh paths so unmanaged local OAuth state cannot satisfy governed authority.

Build A Provider From Security-Scheme Metadata

provider =
  Pristine.OAuth2.Provider.from_security_scheme!(
    "oauth",
    %{
      "type" => "oauth2",
      "x-pristine-flow" => "authorizationCode",
      "x-pristine-token-content-type" => "application/x-www-form-urlencoded",
      "flows" => %{
        "authorizationCode" => %{
          "authorizationUrl" => "https://example.com/oauth/authorize",
          "tokenUrl" => "https://example.com/oauth/token",
          "scopes" => %{"read" => "Read access"}
        }
      }
    }
  )

Build An Authorization Request

This example is standalone OAuth setup. The env values are direct local inputs and are not governed authority.

{:ok, authorization_request} =
  Pristine.OAuth2.authorization_request(
    provider,
    client_id: "provider-client-id",
    redirect_uri: "http://localhost:4000/callback",
    scopes: ["read"],
    generate_state: true,
    pkce: true
  )

Exchange A Code

OAuth token exchange uses a runtime client context for transport and serializer selection. This direct CLIENT_ID and CLIENT_SECRET example is standalone compatibility.

client =
  Pristine.Client.new(
    base_url: "https://example.com",
    transport: Pristine.Adapters.Transport.Finch,
    transport_opts: [finch: MyApp.Finch],
    serializer: Pristine.Adapters.Serializer.JSON
  )

{:ok, token} =
  Pristine.OAuth2.exchange_code(
    provider,
    code,
    context: client.context,
    client_id: "provider-client-id",
    client_secret: "provider-client-secret"
  )

Persisted Tokens

Pristine.OAuth2.SavedToken uses Pristine.OAuth2 directly for refresh flows. Browser launch and loopback callback capture remain optional adapter seams on top of the runtime boundary.

That means a provider SDK can expose a thin helper layer over Pristine.OAuth2 without reimplementing token persistence or refresh merge behavior.

In governed mode, use the selected authority materializer to produce a Pristine.GovernedAuthority instead of loading Pristine.Adapters.TokenSource.File or refreshing Pristine.OAuth2.SavedToken from local state.