All notable changes to this project are documented here. The format follows Keep a Changelog, and this project adheres to Semantic Versioning.

[0.1.0] — 2026-08-08

First release.

Everything below has been verified end to end against production OpenFeed: OIDC discovery, private_key_jwt at the PAR, token and introspection endpoints, PAR, the authorization-code exchange, grant_id recovery via introspection, DPoP-bound resource calls, multi-page pagination, token refresh, and the app-level endpoints.

Requires

  • Elixir 1.17+ and OTP 27+. The OTP floor comes from oidcc, which does not compile on OTP 26; both packages check and raise a clear error. Verified in CI across Elixir 1.17-1.20.

Added

  • OpenFeed — top-level facade. {OpenFeed, config} starts the OIDC discovery worker in a supervision tree.

  • OpenFeed.Config — injected configuration struct with validation. Nothing in this package reads application environment.

  • OpenFeed.Scopes — shorthand atoms for OpenFeed's scope strings.

  • OpenFeed.KeyStore behaviour, with File and Env implementations. Keys are never generated implicitly; see the README for why.

  • mix openfeed.gen.key and mix openfeed.jwks.

  • OpenFeed.Dpop — RFC 9449 PS256 proofs, including exp/nbf and clock-skew tolerance.

  • OpenFeed.Auth and OpenFeed.Tokens — PAR + PKCE authorization, code exchange, refresh, client credentials, introspection.

  • OpenFeed.ProviderConfiguration — discovery worker, with the introspection metadata override OpenFeed's discovery document requires.

  • OpenFeed.Client — DPoP transport, links.next pagination, lazy stream/4, retries with jittered backoff.

  • OpenFeed.Sharing — a function for each of the 16 sharing-api paths.

  • OpenFeed.Error — typed errors classified by a stable :kind, so callers can distinguish a revoked grant from a subject mismatch (both HTTP 403).

  • OpenFeed.ReqHttpAdapter:oidcc_http_adapter backed by Req, replacing httpc, which intermittently wedges against auth.openfeed.au.

  • OpenFeed.Amount.to_decimal/1 — handles both wire formats OpenFeed uses for money: ISO 20022 strings in banking, JSON numbers in energy.

  • OpenFeed.Energy.net_usage/1, has_reads?/1, reads/1, read_value/1 — handle the readUType discriminator in usage payloads. Reading only the interval variant silently reports zero for daily-read meters.

Fixed

  • A revoked grant discovered via token refresh was reported as :unauthorized, so callers retried a refresh that could never succeed while the grant looked healthy. invalid_grant on refresh is now :grant_revoked — OpenFeed sweeps refresh tokens when a grant is revoked, so this is the normal way a client learns a consumer disconnected. Not applied to exchange_code/3, where invalid_grant means a stale authorization code.
  • authorize_url/2 no longer forces grant_management_action=create. OpenFeed treats the action as optional and infers it from grant_id presence.
  • Corrected the authorize_url/2 docs: query and revoke are advertised in grant_management_actions_supported but are not authorization-endpoint actions.

Documentation

  • A Grant management topic covering the consent lifecycle, amendment, polling for revocations, and what the authorised account id lists are not.
  • A Collecting data tutorial and a Cost and cadence topic, both wired into the docs. The README gained a Collecting data section; it previously covered setup and key management and said nothing about reading data.
  • test/documentation_test.exs runs the documented examples against a stub, so the guides cannot drift into code that no longer works.

Requires

  • oidcc ~> 3.8 — the first release with pluggable HTTP adapters (erlef/oidcc#528).