# Security & data handling at openfeed

> The security posture developers build on: openfeed as an accredited CDR recipient software product, FAPI 2.0 authentication, and data-pipeline controls.

- Category: security
- Audience: developers
- Updated: 2026-07-17
- Canonical: https://openfeed.au/resources/security-and-data-handling

---

openfeed is built by the team that operates production CDR infrastructure — security is
foundational, not bolted on. This is the platform posture your app inherits when you build on
openfeed.

## openfeed in the Consumer Data Right ecosystem

openfeed is a **software product** operated by Biza Pty Ltd, an **Accredited Data
Recipient** under Australia's Consumer Data Right. **openfeed** is registered on the
[CDR Register](https://www.cdr.gov.au/find-a-provider?provider=DRSP000374) maintained by the Australian Competition
and Consumer Commission (ACCC), and has completed the
[Conformance Test Suite for data recipients](https://www.cdr.gov.au/for-providers/conformance-test-suite-data-recipients).

When you build on openfeed, you're building on top of a validated CDR Software Product inside the
CDR ecosystem, you don't need to become an ADR yourself.

## What openfeed handles for you

The CDR ecosystem is many-sided and evolving. **openfeed** absorbs that complexity so your app can
stay focused on your product:

- **100+ data holder connections**: Every bank and energy retailer implements the CDR against
  their own systems, with their own access, endpoint quirks, and edge cases. openfeed
  maintains those connections continuously so you code against one interface. Users encountering issues
  with their providers can resolve them via openfeed and have all the downstream apps reap the benefits.
- **CDR mandated requirements**: Mutual TLS, dynamic client registration against the CDR
  Register, participant PKI issuance and rotation, and per-holder discovery — all handled
  centrally by openfeed.
- **Data normalisation**: Each holder implements the CDR Data Standards with subtle differences.
  openfeed normalises accounts, transactions, meters, usage, and DER into a consistent shape you
  can code against once — the same call works across every holder and **openfeed** continuously improves
  how it maps data on a per-holder basis.
- **Availability and resilience**: openfeed tracks holder health, retries with backoff when
  specific holders are degraded, and monitors published [rectification schedules](https://www.cdr.gov.au/for-providers/rectification-schedules) so your
  app isn't caught out by known issues upstream. We will publish individual data holders we identify
  as having ongoing data quality issues.
- **Standards evolution**: The CDR Data Standards change over time. openfeed tracks the versions
  and adapts ingestion so your integration doesn't churn every release.

## Data flow at a glance

CDR Consumers authorise their Data Holder, their bank or energy retailer, to share data with
openfeed under the Consumer Data Right. When a consumer chooses to share with your app, openfeed
brokers an **onward disclosure grant** and your app fetches the shared data over a FAPI 2.0 hardened API.
Your app never touches raw CDR credentials or upstream data holder connections.

## Security in Depth

The openfeed Sharing API is **FAPI 2.0 compliant**, the highest standard of security profile published by the
OpenID Foundation, purpose-built for financial-grade data sharing. Your app inherits that bar
simply by authenticating against openfeed.

The [Quickstart](/resources/quickstart) covers the configuration but for those interested in the deeper complex parts this section is for you.

### Token handling in the platform

The openfeed Sharing API is a FAPI 2.0 resource server. The platform issues sender-constrained
tokens through a hardened authorisation flow and enforces grant state live on every request. New
client registrations default to the Recommended profile (`private_key_jwt` + DPoP).

### Confidential clients

- **Confidential-only clients**: There are no public clients on openfeed. All profiles require a server-side credential. 
  The resource-owner password grant is rejected outright.
- **`private_key_jwt` client authentication (Recommended)**: Client-authentication assertions are
  signed with your app keypair (PS256/RSA) and verified by the auth-server against
  your published `jwks_uri` or your staticly uploaded public keyset.

### Authorisation request hardening

- **Pushed Authorization Requests (PAR), mandatory for all clients**: Every authorisation
  request is pushed server-to-server over an authenticated back channel and exchanged for a
  single-use `request_uri`. A plain authorisation redirect without a prior PAR is rejected.
  Request parameters — including `redirect_uri`, scopes, PKCE challenge, and grant-management
  instructions — never traverse the browser, so they cannot be inspected, tampered with, or
  replayed in transit.
- **Short-lived, single-use `request_uri`**: The PAR response carries `expires_in: 60`. The
  `request_uri` is one-time-use at the point of authorisation. This shrinks the window for
  request-leak CSRF and browser-swapping attacks to seconds.
- **PKCE with S256, required**: Every authorisation code is bound to a per-request PKCE
  challenge (`code_challenge_method=S256`). An intercepted authorisation code is useless without
  the matching verifier, and the verifier never leaves your server.
- **`redirect_uri` carried inside the authenticated PAR**: Redirect URIs are validated at runtime
  from the authenticated PAR body rather than from a pre-registration list. This closes
  open-redirect vectors while eliminating the pre-registration foot-gun — the dashboard
  registration form has no redirect URI field for this reason.
- **Authorization code binding to DPoP key**: When using the Recommended profile the
  authorisation code is cryptographically bound to your DPoP key at issuance, so it cannot be
  exchanged by a different client even if intercepted.
- **Issuer identification in the authorisation response**: The authorisation response includes
  an `iss` parameter (RFC 9207) which clients must verify, preventing mix-up attacks where a
  malicious authorisation server substitutes its response for a legitimate one.
- **Authorization codes are single-use and short-lived**: A code that has already been presented
  to the token endpoint is permanently invalid; a code that is never presented expires within
  ~60 seconds.

### Grant management via authorisation

- **Grants are established through the authorisation request itself**: Per the OIDF
  [Grant Management for OAuth 2.0](https://openid.net/specs/fapi-grant-management.html) spec,
  grants are created, queried, and replaced via `grant_management_action` (and `grant_id`) in
  the PAR body — not a mutable side API that can be called independently. See
  [Grant management & lifecycle](/resources/grant-management-and-lifecycle) for the PAR
  attributes table.
- **`grant_id` claim on every data token**: Access tokens carry a `grant_id` claim identifying
  the bound disclosure grant. A token without a `grant_id` cannot call any data endpoint.

### Token binding and properties

- **DPoP sender-constrained (bound) access tokens (Recommended)**: Every access token is
  cryptographically bound to your DPoP keypair (RFC 9449). Tokens are presented under the `DPoP`
  scheme — not `Bearer` — and each API call must include a fresh, single-use DPoP proof signed
  over the HTTP method and request URL, with an `ath` claim hashing the exact access token. A
  token exfiltrated from a log, proxy, or wire capture is useless without your DPoP private key.
  See the `Authorization: DPoP` example in the [Quickstart](/resources/quickstart).
- **Two separate keypairs for two separate jobs**: Client-assertion signing uses your app keypair
  (PS256/RSA); DPoP proof signing uses a distinct DPoP keypair (PS256 is rejected for DPoP). 
  The DPoP private key is never published in your JWKS. Compromising one keypair does not compromise the other.
- **Audience-bound tokens**: Access tokens are minted for `api.openfeed.au` implicitly bound at request establishment.
  A token issued without this audience binding fails validation on every data call. A token
  issued for another resource cannot be replayed against the sharing API.
- **Minimum 128-bit entropy on all credentials**: Authorisation codes, access tokens, and refresh
  tokens are generated with at least 128 bits of entropy, making brute-force guessing
  computationally infeasible.
- **Short access-token lifetimes paired with refresh tokens**: Access tokens are short-lived
  (on the order of an hour). Refresh tokens carry the long-lived session, keeping the blast
  radius of a leaked access token small. Refresh tokens also let you rotate your
  sender-constraining DPoP keypair without losing the user's grant.

### Runtime enforcement

- **Live grant state resolved on every request**: Both consumer consent (`grantStatus`) and
  metering state (`meteringState`) are resolved at the API boundary on every call — there is no
  cached authorisation. A revoked or suspended grant fails immediately before any data leaves
  the platform.
- **Minimal introspection surface**: Introspection responses expose only `{active, grant_id}` —
  no `authorisation_details`, no personal information, no account identifiers. Nothing sensitive
  is reachable through introspection.

## Data pipeline controls

openfeed's ingestion pipeline applies controls to Consumer Data as it enters and moves through the
platform — including but not limited to **data masking and redaction** of sensitive fields.
Sensitive identifiers are neutralised before data reaches sharing-API responses, so your app
receives fields fit for storage and use.

## Consent & grant safety

- **openfeed manages the consumer's consents** end-to-end. Grants are the durable, revisioned
  handle for each share; consent events are recorded against each grant.
- **Revocation is live**: When a consumer revokes a grant, subsequent data calls return
  `403 disclosure_grant_required` immediately — no cached authorisation.
- **State is enforced per request**: Both consumer consent (`grantStatus`) and metering state
  (`meteringState`) are resolved live at the API boundary; you can't accidentally read data on a
  stale grant.

See [Grant management & lifecycle](/resources/grant-management-and-lifecycle) for the developer's
side of the model.

## Independent assurance

Beyond the CDR accreditation covered above, Biza Pty Ltd maintains:

- **ISO 27001**: information security management standard including **ISO27017** and **ISO27018** extensions.
- **SOC 2 Type 2**: independent assurance of security, availability, and confidentiality
  controls.
- **ASAE 3150**: assurance audits underpinning Biza's CDR Data Recipient accreditation.

The same infrastructure powers openfeed.

## Your side

The platform gives you a secure foundation; your app closes the loop. See **Stage 4** of
[Path to production](/resources/path-to-production) for openfeed's expectations of how
you handle the data your app receives — token storage, retention, and Privacy Act obligations.
