OIDC authentication flows: Pushed Authorisation Requests, authorisation URLs, code exchange, and client-credentials tokens.
Moneyhub's auth flow has three shapes depending on what you're doing:
- Bank connection (AIS) - drive the user through
/oidc/auth(or a PAR-backedrequest_uri) to connect a bank account, then exchange the returnedcodefor tokens. - Payments (PIS) - same shape, but the
claimsparameter carries amh:payment/mh:recurring_payment/mh:standing_orderclaim instead of (or alongside) AIS scopes. - Ongoing data access - once a user is registered (their
subis known from step 1'sid_token), fetch aclient_credentialstoken scoped to that user viatoken_for_user/2and call the data API directly - no further browser redirect needed.
Example: connect a bank account (ongoing access, new user)
claims = MoneyHub.Claims.new() |> MoneyHub.Claims.put_sub()
{:ok, %{url: url, request_uri: request_uri}} =
MoneyHub.Auth.pushed_authorisation_request(config,
scope: MoneyHub.Scopes.ais_offline(),
claims: claims
)
# redirect the user's browser to `url`, they authenticate at their
# bank, and your redirect_uri receives `?code=...`
{:ok, tokens} = MoneyHub.Auth.exchange_code(config, code)
{:ok, claims} = MoneyHub.Auth.IdToken.verify(tokens.id_token, config)
user_id = claims["sub"]Example: get a data token for an already-connected user
{:ok, token} = MoneyHub.Auth.token_for_user(config, user_id)
{:ok, accounts} = MoneyHub.Accounts.list(config, token.access_token)
Summary
Functions
Builds an /oidc/auth authorisation URL.
Exchanges an authorisation code (returned to your redirect_uri) for
tokens at /oidc/token, using authorization_code grant.
Sends a Pushed Authorisation Request (PAR) to /oidc/request and
returns the request_uri to embed in the authorisation URL, alongside
the ready-to-use full URL.
Exchanges a refresh_token for a fresh token set, using refresh_token
grant. Requires the original authorisation to have included
offline_access.
Fetches a client_credentials token, optionally scoped to a specific
Moneyhub user (via the sub claim) for ongoing data access.
Types
Functions
@spec authorisation_url( MoneyHub.Config.t(), keyword() ) :: String.t()
Builds an /oidc/auth authorisation URL.
Pass either the same options as pushed_authorisation_request/2
(:scope, :claims, :state, ...) to build a URL with parameters
inline, or request_uri: (as returned by
pushed_authorisation_request/2) to build a PAR-backed URL.
@spec exchange_code(MoneyHub.Config.t(), String.t(), keyword()) :: {:ok, tokens()} | {:error, MoneyHub.Error.t()}
Exchanges an authorisation code (returned to your redirect_uri) for
tokens at /oidc/token, using authorization_code grant.
@spec pushed_authorisation_request( MoneyHub.Config.t(), keyword() ) :: {:ok, %{request_uri: String.t(), expires_in: integer(), url: String.t()}} | {:error, MoneyHub.Error.t()}
Sends a Pushed Authorisation Request (PAR) to /oidc/request and
returns the request_uri to embed in the authorisation URL, alongside
the ready-to-use full URL.
PAR keeps sensitive parameters (notably claims, which can be large and
contain payment payloads) off of the browser's URL bar entirely: only an
opaque request_uri reference is exposed client-side.
Options
:scope- required. A space-delimited scope string, e.g. fromMoneyHub.Scopes.:claims- aMoneyHub.Claimsmap, or any term accepted byJason.encode!/1, to be embedded as theclaimsparameter.:state- an opaque value round-tripped back on redirect. Generated randomly if omitted.:redirect_uri- overridesconfig.redirect_urifor this request.:response_type- defaults to"code".
@spec refresh_token(MoneyHub.Config.t(), String.t()) :: {:ok, tokens()} | {:error, MoneyHub.Error.t()}
Exchanges a refresh_token for a fresh token set, using refresh_token
grant. Requires the original authorisation to have included
offline_access.
@spec token_for_user(MoneyHub.Config.t(), String.t() | nil, keyword()) :: {:ok, tokens()} | {:error, MoneyHub.Error.t()}
Fetches a client_credentials token, optionally scoped to a specific
Moneyhub user (via the sub claim) for ongoing data access.
Once a user has completed an AIS connection (their sub known from the
id_token of exchange_code/3), call this to obtain a fresh
access_token for reading that user's data - no browser interaction
required.