An Elixir client for OpenFeed — Australian Consumer Data Right banking and energy data.
OpenFeed implements the FAPI 2.0 Security Profile. This library's job is to
make that a detail you do not think about: PAR, PKCE S256, DPoP proofs on
every call, private_key_jwt client authentication, and the key management
that implies.
Using Ash? See
ash_openfeed, which builds on this and adds grant persistence, token refresh and an installer.
Where to look
| For | See |
|---|---|
| Configuration | OpenFeed.Config |
| Keys | OpenFeed.KeyStore, mix openfeed.gen.key, mix openfeed.jwks |
| The consent flow | OpenFeed.Auth |
| Reading data | OpenFeed.Sharing |
| Errors | OpenFeed.Error |
Setting up
Generate a key and register its public half with OpenFeed:
mix openfeed.gen.key --path priv/openfeed.jwk
mix openfeed.jwks --path priv/openfeed.jwkBuild a config and add this module to your supervision tree, which starts the OIDC discovery worker so metadata is fetched once rather than per call:
config =
OpenFeed.Config.new!(
client_id: System.fetch_env!("OPENFEED_CLIENT_ID"),
redirect_uri: "https://my.app/openfeed/callback",
key_store: {OpenFeed.KeyStore.File, path: "priv/openfeed.jwk"}
)
children = [{OpenFeed, config}, MyApp.Repo, MyAppWeb.Endpoint]The consent flow
# 1. Starting out — keep all three values in the session.
flow = OpenFeed.Auth.new_flow()
{:ok, url} = OpenFeed.authorize_url(config, Enum.to_list(flow))
redirect(conn, external: url)
# 2. At your callback, having checked `state` matches.
{:ok, tokens} =
OpenFeed.exchange_code(config, code,
nonce: flow.nonce,
pkce_verifier: flow.pkce_verifier
)
# 3. Later, when the access token is close to expiry.
{:ok, tokens} = OpenFeed.refresh(config, tokens.refresh_token, tokens.sub)Reading data
{:ok, accounts} = OpenFeed.Sharing.banking_accounts(config, tokens.access_token)
{:ok, transactions} =
OpenFeed.Sharing.banking_transactions(
config,
tokens.access_token,
account["accountId"],
oldest_date: Date.add(Date.utc_today(), -365)
)Branch on OpenFeed.Error's :kind rather than on HTTP status — in
particular, :grant_revoked means stop and ask the consumer to reconnect,
while :subject_mismatch is also a 403 but means something has gone wrong on
your side.
Summary
Functions
Child spec for the OIDC discovery worker, so {OpenFeed, config} works
directly in a supervision tree.
Functions
@spec child_spec(OpenFeed.Config.t()) :: Supervisor.child_spec()
Child spec for the OIDC discovery worker, so {OpenFeed, config} works
directly in a supervision tree.
Delegates to OpenFeed.ProviderConfiguration.