NZ Banking Data Security Profile v1.0.0

 

Version Control

Version

Date

Author

Comments

v1.0.0

 

Payments NZBaseline Security Profile

Introduction

This document is based on the OpenID Foundation's Financial API Read+Write specification document, FAPI-RW, which in turn is based on the Read only specification document. The NZ Banking Data profile will further shape these two base profiles in some cases tightening restrictions and in others loosening requirements using keywords. Please see the introduction to FAPI-RW for a general introduction to the aims of this document.

The NZ Banking Data Profile outlines the differences between the FAPI-RW with clauses and provisions necessary to reduce delivery risk for an API Provider's OP.

Notation Conventions

The key words "shall", "shall not", "should", "should not", "may", and "can" in this document are to be interpreted as described in ISO Directive Part 2. These key words are not used as dictionary terms such that any occurrence of them shall be interpreted as key words and are not to be interpreted with their natural language meanings.

1. Scope

This part of the document specifies the method of

  • Applications to obtain the OAuth tokens in an appropriately secure manner for financial data access;
  • Applications to use OpenID Connect to identify the customer; and
  • Using tokens to interact with the REST endpoints that provides financial data;

This document is applicable to higher risk use cases which includes commercial and investment banking.

2. Normative References

The following referenced documents are strongly recommended to be used in conjunction with this document. For dated references, only the edition cited applies. For undated references, the latest edition of the referenced document (including any amendments) applies.

[FAPI] - FAPI ReadOnly profile [FAPI]: http://openid.net/specs/openid-financial-api-part-1.html

[FAPI-RW] - FAPI Read+Write profile [FAPI-RW]: http://openid.net/specs/openid-financial-api-part-2.html

[OIDC] - OpenID Connect Core 1.0 incorporating errata set 1 [OIDC]: http://openid.net/specs/openid-connect-core-1_0.html

[MTLS] - Mutual TLS Profile for OAuth 2.0 [MTLS]: https://tools.ietf.org/html/draft-ietf-oauth-mtls-03

3. Terms and Definitions

For the purpose of this document, the terms defined in [FAPI ReadOnly profile] FAPI, [FAPI Read+Write profile] FAPI-RW and [OpenID Connect Core] OIDC apply.

4. Symbols and Abbreviated Terms

API Provider - provides APIs in a manner that complies with the API Standards (e.g. Account Information and Payment Initiation APIs), and connects those APIs with a Third Party.

Third Party - the entity that consumes an API in a manner that complies with the API Standards.

Customer - a natural or legal person that operates banking accounts.

5. Read and Write API Security Profile

5.2 NZ Banking Data API Security Provisions

5.2.1 Introduction

The NZ Banking Data API Security Profile does not distinguish between the security requirements from a technical level between "read" and "write" resources. The security requirements for accessing Customer resources held at API Providers requires more protection level than a basic RFC6749 supports.

As a profile of The OAuth 2.0 Authorization Framework, this document mandates the following to the NZ Banking Data APIs.

5.2.2 Authorization Server

The Authorization Server

  1. shall support confidential clients;
  2. may support public clients;
  3. shall secure its token endpoint using mutually authenticated TLS;
  4. shall only support the response_type value code id_token;
  5. shall authenticate the confidential client at the Token Endpoint using one of the following methods:
    1. tls_client_auth as per MTLS (Recommended); or
    2. private_key_jwt or 'client_secret_jwt` (Recommended); or
    3. client_secret_basic or client_secret_post provided the client identifier matches the client identifier bound to the underlying mutually authenticated TLS session (Allowed - but this support will be reviewed for a future version of the Security Profile);
  6. shall issue an ID Token in the token response when openid was included in the requested scope as in Section 3.1.3.3 of OIDC with its "sub" value corresponding to the "Intent Id" and optional acr value in ID Token.
  7. may support refresh tokens.
  8. shall provide a discovery endpoint that does not require a client certificate to authenticate using a TLS certificate that should be trusted by the user agent.

Further, if it wishes to provide the authenticated user's identifier to the client in the token response, the authorization server

  1. shall issue an ID Token in the token response when openid was included in the requested scope as in Section 3.1.3.3 of OIDC with its sub value corresponding to the authenticated user and mandatory acr value in ID Token.
  2. shall support Request Objects passed by value as in clause 6.3 of OIDC.

5.2.3 Public Client

NZ Banking Data OPs can support Public Clients at their discretion.

Should an OP wish to support public clients all provisions of FAPI-RW will be adhered too with exceptions below;

  1. shall request user authentication at appropriate level

5.2.4 Confidential Client

A Confidential Client

  1. may use separate and distinct Redirect URI for each Authorization Server that it talks to;
  2. shall accept signed ID Tokens;

6. Accessing Protected Resources

6.1 Introduction

The FAPI endpoints are OAuth 2.0 protected resource endpoints that return various financial information for the resource owner associated with the submitted access token.

6.2 Access Provisions

6.2.1 Protected resources provisions

The resource server with the FAPI endpoints

  1. shall mandate mutually authenticated TLS;
  2. shall verify that the client identifier bound to the underlying mutually authenticated TLS transport session matches the client that the access token was issued to;

6.2.2 Client Provisions

The confidential client supporting this document

  1. shall use mutually authenticated TLS; and
  2. shall supply the last time the customer logged into the client as defined by FAPI clause 6.2.2.3; and
  3. shall supply the customer's IP address if this data is available as defined by FAPI clause 6.2.2.4;
  4. shall supply the merchant's IP address if this data is available in the x-merchant-ip-address header, e.g., x-fapi-customer-ip-address: 198.51.100.119;
  5. shall supply the customer's user agent if this data is available in the x-customer-user-agent header,

Further, the client

  1. may supply the customers authentication context reference (ACR) or applicable in the x-fapi-customer-acr header, e.g., x-fapi-customer-acr;

7. Request Object Endpoint

7.1 Introduction

  1. OPs shall not support request_uri, OIDC Request Object by Reference.
  2. OPs shall support Request Objects passed by value as in clause 6.3 of OIDC.

8. Security Considerations

8.1 TLS Considerations

The TLS considerations in FAPI section 7.1 shall be followed.

The TLS considerations in FAPI-RW section 8.5 shall be followed.

8.2 Message Source Authentication Failure and Message Integrity Protection Failure

It is not mandated that the Authorization request and response are authenticated. To provide message source authentication and integrity protection:

  1. Authorization servers should support the Request Object Endpoint as per FAPI-RW clause 7
  2. Authorization servers should return an ID token as a detached signature of the authorization response as per FAPI-RW part 2 clause 5.2.2.3.

8.3 Message Containment Failure

The Message containment failure considerations in FAPI section 7.4 shall be followed.

8.4 JWS Algorithm Considerations

The JWS algorithm considerations in FAPI-RW section 8.6 shall be followed.

As a downgrade for FAPI-RW section 8.6.2: 

  1. Both clients and authorisation servers may use algorithms that use RSASSA-PKCS1-v1_5 (e.g. RS256). However, this is not recommended, and this support will be reviewed for a future version of the Security Profile.

Security Architecture

OAuth 2.0

OAuth 2.0 will be the foundational framework for API Security for the NZ Banking Data API Standard. OAuth 2.0 itself is a framework which can be deployed in many ways, some of them completely incompatible with financial models. In order to securely use the OAuth 2.0 framework, a profile must exist by which both Third Parties and API Providers are certified to have correctly configured their clients and servers.

OIDC

The OpenID Connect Request object uses exactly the same claims object for specifying claim names, priorities, and values as OAuth 2.0. However if the Request object is used, the Claims object becomes a member in an assertion that can be signed and encrypted, allowing the API Provider to authenticate the request from the Third Party and ensure it hasn't been tampered with. The OpenID Connect Request object can either be passed as a query string parameter, or can be referenced at an endpoint that could theoretically be protected by MATLS. The use of JWT Request objects by reference is not supported due a number of delivery risks and remaining security concerns.

In addition to specifying a ticket, the Third Party can optionally require a minimum strength of authentication context or request to know how long ago the user was actually authenticated. Multiple tickets could be passed if necessary. Everything is fully specified. Vendors who implement this feature are not creating a one-off proprietary feature, they are simply supporting the OpenID Connect standard.

Full accountability is available as required by all participants. Not only can the API Provider prove that they received the original request from the Third Party, but the Third Party can prove that the access token that comes back was the token that was intended to be affiliated to this specific Intent Id.

FAPI

The Financial API working group in the OpenID Foundation has created a draft standard for configuration of Financial-grade API security regimes. If any FAPI-compliant vendor can participate in the NZ Banking Data API ecosystem, it means that vendors can work to the standard and reach many customers, rather than having to create different solutions for different banking platforms. 

Hybrid Flow Request with Intent Id

This section describes parameters that should be used with an hybrid grant flow request so that an Intent Id can be passed from the Third Party to an API Provider for minimum conformance for the NZ Banking Data API Profile.

Prior to this step, 

  1. The Third Party would have already registered an intent (with an Intent Id) with an API Provider. This is achieved by using one of the account information or payment initiation consent APIs.
  2. The API Provider would have responded with an Intent Id (this is the unique identifier for the consent resource).

Authorization Request

This section describes the bare minimum set of Authorization Request parameters that an API Provider must support. The definitive reference is specified in OIDC Section 3.3.2.1 (Authentication Request) and OIDC Section 3.1.2.1 (Authentication Request)

All API Providers MUST support the issuance of OIDC ID tokens, a Third Party MAY request that an ID token is issued. 

This is a non-normative example of the Authorization Request:

GET /authorize?
response_type=code%20id_token
&client_id=s6BhdRkqt3
&state=af0ifjsldkj&
&scope=openid
&nonce=n-0S6_WzA2Mj
&redirect_uri=https://api.mytpp.com/cb
&request=CJleHAiOjE0OTUxOTk1ODd.....JjVqsDuushgpwp0E.5leGFtcGxlIiwianRpIjoiM....JleHAiOjE0.olnx_YKAm2J1rbpOP8wGhi1BDNHJjVqsDuushgpwp0E

Parameters

Parameter

NZ Banking Data Profile

Notes

scopeRequired

Third Parties MUST specify the scope that is being requested.

At a minimum the scope parameter MUST contain openid

The scopes MUST be a sub-set of the scopes that were registered during Client Registration with the API Provider.

response_type

Required

OAuth 2.0 requires that this parameter is provided. Value is set to  'code id_token', 'code id_token token' or 'code'

Third Parties MUST provide this parameter and set its value to one of the three above depending on what the API Provider supports as described in its well-known configuration endpoint.

The values for these parameters MUST match those in the Request Object, if present.

Note: risks have been identified with "code" flow that can be mitigated with hybrid flow, the NZ Banking Data Profile allows API Providers to indicate what grant types are supported using the standard well-known configuration endpoint. RP's must take care in validating that code swap attacks have not been attempted.

client_idRequired

Third Parties MUST provide this value and set it to the Client Id issued to them by the API Provider to which the authorization code grant request is being made.

redirect_uriRequired

Third Parties MUST provide the URI to which they want the resource owner's user agent to be redirected to after authorization.

This MUST be a valid, absolute URL that was registered during Client Registration with the API Provider.

stateRecommended

Third Parties MAY provide a state parameter.

The parameter may be of any format and is opaque to the API Provider.

If the parameter is provided, the API Provider MUST play back the value in the redirect to the Third Party.

If the parameter is provided, the API Provider MUST include the s_hash in the ID Token.

nonceRequired

Third Parties MUST provide a nonce parameter.

Used to help mitigate against replay attacks. 

If the parameter is provided, the API Provider MUST be replayed in the ID Token.

requestRequired

The Third Party MUST provide a value for this parameter.

The Request Object parameter MUST contain a JWS that is signed by the Third Party.

The JWS payload MUST consist of a JSON object containing a Request Object as per OIDC Section 6.1.

Request Object

This section describes the Request Object which is used in the request Authorization Request parameter. The definitive reference is specified in OIDC Section 6.1 (Request Object). All standards and guidance MUST be followed as per the OIDC specification.

The Request Object MUST contain a Claims section with:

  • openbanking_intent_id

The Request Object MAY contain Claims to be retrieved via the UserInfo endpoint only if the endpoint is made available and listed on the well known configuration endpoint on the authorisation server.

The Request Object MAY contain additional Claims to be requested should the API Provider's Authorization Server support them, these Claims will be listed on the OIDC Well Known configuration endpoint.

As per OIDC - when the request parameter is used, the OpenID Connect request parameter values contained in the JWT supersede those passed using the OAuth 2.0 request syntax. However, parameters MAY also be passed using the OAuth 2.0 request syntax even when a Request Object is used.

Within a "claims" field the "essential" field is required to indicate whether the Claim being requested is an Essential Claim. If the value is true, this indicates that the claim is an Essential Claim.

For instance, the claim request:

  "auth_time": {"essential": true}

can be used to specify that it is essential to return an auth_time Claim. If the value is false, it indicates that it is a Voluntary Claim. The default is false. By requesting Claims as Essential Claims, the RP indicates to the End-User that releasing these Claims will ensure a smooth authorization for the specific task requested by the End-User. Note that even if the Claims are not available because the End-User did not authorize their release or they are not present, the Authorization Server MUST NOT generate an error when Claims are not returned, whether they are Essential or Voluntary, unless otherwise specified in the description of the specific claim.

This is a non-normative example of the Request Object JWS - without Base64 encoding:

{
	"alg": "PS256",
	"kid": "GxlIiwianVqsDuushgjE0OTUxOTk"
}
.
{
	"aud": "https://api.alphanbank.com",
	"iss": "s6BhdRkqt3",
	"response_type": "code id_token",
	"client_id": "s6BhdRkqt3",
	"redirect_uri": "https://api.mytpp.com/cb",
	"scope": "openid payments accounts",
	"state": "af0ifjsldkj",
	"nonce": "n-0S6_WzA2Mj",
	"max_age": 86400,
	"claims": {
		"userinfo": {
			"openbanking_intent_id": {
				"value": "urn:alphabank-intent-58923",
				"essential": true
			}
		},
		"id_token": {
			"openbanking_intent_id": {
				"value": "urn-alphabank-intent-58923",
				"essential": true
			},
			"acr_values": {
				"essential": true,
				"values": ["urn:openbanking:nz:sca",
					"urn:openbanking:nz:ca"
				]
			}
		}
	}
}
.
<<signature>>

Claims

Where appropriate follow the JWT Good Practice Guides http://self-issued.info/docs/draft-sheffer-oauth-jwt-bcp-00.html#rfc.section.3.1 

FieldNZ Banking Data ProfileNotes
aud

Required

The aud value SHOULD be or include the API Provider's Issuer Identifier URL.

iss

Required

The iss value SHOULD be the Client Id of the Third Party, unless it was signed by a different party than the Third Party.

scopeRequired

Third Parties MUST specify the scope that is being requested.

At a minimum the scope parameter MUST contain openid

The scopes MUST be a sub-set of the scopes that were registered during Client Registration with the API Provider.

response_typeRequired

Third Parties MUST provide this field and set its value to 'code id_token', 'code id_token token' or 'code' depending on what the API Provider supports as described in its well-known configuration endpoint.

The values MUST match those in the request parameter.

client_idRequiredThird Parties MUST provide this value and set it to the Client Id issued to them by the API Provider to which the authorization code grant request is being made.
redirect_uriRequired

Third Parties MUST provide the URI to which they want the resource owner's user agent to be redirected to after authorization.

This MUST be a valid, absolute URL that was registered during Client Registration with the API Provider.

stateRecommended

Third Parties MAY provide a state parameter.

The parameter may be of any format and is opaque to the API Provider.

If the parameter is provided, the API Provider MUST play back the value in the redirect to the Third Party.

If the parameter is provided, the API Provider MUST include the s_hash in the ID Token.

nonce

Required

Third Parties MUST provide a nonce parameter.

Used to help mitigate against replay attacks. 

If the parameter is provided, the API Provider MUST be replay the nonce value in the ID Token.

max_ageOptional

Third Parties MAY provide a maximum authentication age parameter.

This specifies the allowable elapsed time in seconds since the last time the End-User was actively authenticated by the API Provider. If the elapsed time is greater than this value, the API Provider MUST attempt to actively re-authenticate the Customer. (The max_age request parameter corresponds to the OpenID 2.0 PAPE [OpenID.PAPE] max_auth_age request parameter.)

If the parameter is provided, the API Provider MUST include an auth_time Claim value in the ID Token.

openbanking_intent_id

Required

It's acknowledged that this field may duplicate the value in "sub" for many providers.

Third Parties MUST provide a openbanking_intent_id. This is a unique and non-repeating identifier containing the Intent Id for which this authorisation is requested.

The Intent Id MUST be the identifier for an intent returned by the API Provider to Third Party that is initiating the authorisation request.

The naming of openbanking_intent_id will be reviewed in a following version of the Security Profile.

acr_values

Optional

Third Parties MAY provide an array that specifies the acr values that the API Provider Authorization Server is being requested to use for processing this Authentication Request, with the values appearing in order of preference. The values MUST be one or both of:

  • urn:openbanking:nz:sca - to indicate that strong customer authentication must be carried.
  • urn:openbanking:nz:ca - to request that the customer is authenticated without using strong customer authentication (standard authentication)

It’s entirely within the API Provider's remit to ignore the requested acr_values however the API Provider must reply with what level of authentication was performed. 

Use of the OPTIONAL acr_values claim is interpreted as an expression of Third Party requested authentication mechanism to be applied when authenticating the Customer. The API Provider MAY choose a stronger authentication than requested by the Third Party (in the case of standard authentication) if it determines this is appropriate. If the acr_values claim is not supplied, the API Provider determines authentication requirements.

ID Token

This is a non-normative example of an ID Token returned - with the sub being populated with an EphemeralId of the Intent Id.

{
	"alg": "PS256",
	"kid": "12345",
	"typ": "JWT"
}
.
{
	"iss": "https://api.alphabank.com",
	"iat": 1234569795,
	"sub": "urn:alphabank-intent-58923",
	"acr": "urn:openbanking:nz:sca",
	"openbanking_intent_id": "urn:alphabank-intent-58923",
	"aud": "s6BhdRkqt3",
	"nonce": "n-0S6_WzA2Mj",
	"exp": 1311281970,
	"s_hash": "76sa5dd",
	"c_hash": "asd097d"
}
.
<<signature>>


This is a non-normative example of an ID Token returned - with the identity claims and Intent Id and sub being populated with a user identifier.

{
	"alg": "PS256",
	"kid": "12345",
	"typ": "JWT"
}
.
{
	"iss": "https://api.alphabank.com",
	"iat": 1234569795,
	"sub": "gavin.wong@percolatorly.com",
	"acr": "urn:openbanking:nz:sca",
	"address": "2 Thomas More Square",
	"phone": "+447890130559",
	"openbanking_intent_id": "urn:alphabank-intent-58923",
	"aud": "s6BhdRkqt3",
	"nonce": "n-0S6_WzA2Mj",
	"exp": 1311281970,
	"s_hash": "76sa5dd",
	"c_hash": "asd097d"
}
.
<<signature>>

Claims

Where appropriate please follow the JWT Good Practice Guides http://self-issued.info/docs/draft-sheffer-oauth-jwt-bcp-00.html#rfc.section.3.1 

FieldNZ Banking Data ProfileNotes
aud

Required

As per FAPI-RW and OIDC.

Audience that the ID token is intended for.

OpenID Connect protocol mandates this MUST include the ClientID of the Third Party's OAuth Client.

iss

Required

A JSON string that represents the issuer identifier of the authorization server as defined in RFC7519. When a pure OAuth 2.0 is used, the value is the redirection URI. When OpenID Connect is used, the value is the issuer value of the authorization server.

Issuer of the token.

Token issuer will be specific to the business.

sub

Required


Token subject identifier.

A unique and non-repeating identifier for the subject, i.e the customer.

  • The sub MUST be the same when created by the Authorisation and Token endpoints during the Hybrid flow. 

Non Identity Services Providers:

  • Use the Intent Id for this field.

Identity Services Providers:

  • Value at the discretion of the OP's.
openbanking_intent_id

Required

It's acknowledged that this field may duplicate the value in "sub" for many providers.

A unique and non-repeating identifier containing the Intent Id of the originating request.

The naming of openbanking_intent_id will be reviewed in a following version of the Security Profile.

exp

Required

The validity length will be at the discretion of the Banks provided that it does not impact the functionality of the APIs. For example, an expiry time of 1 second is insufficient for all Resource Requests.
 

Token expiration date/time.

Expressed as an epoch i.e. number of seconds from 1970-01-01T0:0:0Z as measured in UTC. RFC7519.

iat

Required

Token issuance date/time.

Expressed as an epoch i.e. number of seconds from 1970-01-01T0:0:0Z as measured in UTC. RFC7519.

auth_time

Case-Specific 

The date/time the Customer was authorised.

This field MUST be provided when max_age is in the Authorization Request is made or max_age is included as an essential claim. In order to be compliant with the protocol we therefore need to support it.

Expressed as an epoch i.e. number of seconds from 1970-01-01T0:0:0Z as measured in UTC. RFC7519.

nonce

Required by FAPI-RW (Hybrid Flow), and OIDC (Hybrid Flow).

Used to help mitigate against replay attacks.

If the nonce parameter is provided in the Authorization Request, the API Provider MUST replay the nonce in the ID Token.

acr

Required

As per OIDC, marking a claim as "essential" and an API Provider can not fulfil it then an error should not be generated.

Authentication Context Reference.

An identifier that qualifies what conditions the authentication performed satisfied. The acr SHOULD correspond to one of the values requested by the acr_values field on the Request Object however even if not present on the request the API Provider SHOULD populate the acr with a value that attests what level of authentication the API Provider performed.

The values to be provided will be to: 

  • urn:openbanking:nz:ca
  • urn:openbanking:nz:sca

It’s within the API Provider's remit to ignore the requested acr_values however the API Provider must reply with what level of authentication was performed. 

amr

Not required to specify as it is to be soon superseded by Vectors of Trust.

Authentication Methods References.

The methods that are used in the authentication. For example, this field might contain indicators that a password was supplied or OTP initiated.

Note – industry direction is to consolidate on https://datatracker.ietf.org/doc/draft-richer-vectors-of-trust. so expect this field to be replaced shortly. AMR doesn’t give the flexibility to address all the actual particulars of both the authn and the identity that sits behind it.

azpNot required

Authorized party.

OPTIONAL. Authorized party - the party to which the ID Token was issued. If present, it MUST contain the OAuth 2.0 Client ID of this party. This Claim is only needed when the ID Token has a single audience value and that audience is different than the authorized party. It MAY be included even when the authorized party is the same as the sole audience. The azp value is a case sensitive string containing a StringOrURI value.

at_hash

Required

As per Hybrid Flow OIDC.

If the ID Token is issued from the Authorization Endpoint with an access_token value, which is the case for the response_type value code id_token token, this is REQUIRED; otherwise, its inclusion is OPTIONAL.


Access Token hash value.

Its value is the base64url encoding of the left-most half of the hash of the octets of the ASCII representation of the access_token value, where the hash algorithm used is the hash algorithm used in the alg Header Parameter of the ID Token's JOSE Header. For instance, if the alg is RS256, hash the access_token value with SHA-256, then take the left-most 128 bits and base64url encode them. The at_hash value is a case sensitive string.

c_hash

Required

As per Hybrid Flow OIDC.

If the ID Token is issued from the Authorization Endpoint with a code, which is the case for the response_type values code id_token and code id_token token, this is REQUIRED; otherwise, its inclusion is OPTIONAL.

Code hash value.

Its value is the base64url encoding of the left-most half of the hash of the octets of the ASCII representation of the code value, where the hash algorithm used is the hash algorithm used in the alg Header Parameter of the ID Token's JOSE Header.

s_hash

Required

As per FAPI-RW.

If the state value is provided in the Authorization Request.

State hash value.

MUST include state hash, s_hash, in the ID Token to protect the state value - if the state value is provided in the Authorization Request.

Its value is the base64url encoding of the left-most half of the hash of the octets of the ASCII representation of the state value, where the hash algorithm used is the hash algorithm used in the alg Header Parameter of the ID Token's JOSE Header. For instance, if the alg is HS512, hash the code value with SHA-512, then take the left-most 256 bits and base64url encode them. The s_hash value is a case sensitive string.

JSON Security Suite Information

Overview

JWT Best Practice

To be followed where appropriate:

http://self-issued.info/docs/draft-sheffer-oauth-jwt-bcp-00.html#rfc.section.3.1


JWKS Endpoints

Each API Provider will host their own JWKS endpoint. Upon issuance of a certificate a JWK Set will be created or updated for a given Third Party.

All participants should include "kid" and "jku" of the key that was used to sign the payloads. The JKU should be considered a hint only and relying parties should derive and then validate wherever possible the appropriate JWKS endpoint for the message signer.

https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-4.1

Steps for Creating a JWS

Step 1: Select the Certificate and Private Key that will be used for Signing the JWS

As the JWS is used for non-repudiation, it MUST be signed using one of JWS issuer's private keys.

The private key MUST have been used by the issuer to get a signing certificate issued from OB. 

The signing certificate MUST be valid at the time of creating the JWS.

Step 2: Form the JOSE Header

The JOSE header is a JSON object consisting of two fields (claims):

Claim

RFC 7515 Standard ?

Required ?

Description

algYesMandatory

The algorithm that will be used for signing the JWS.

The list of valid algorithms is here https://tools.ietf.org/html/rfc7518#section-3.1.

This MUST be an algorithm that support asymmetric encryption.

kidYes (optional)Mandatory
The "kid" (key ID) Header Parameter is a hint indicating which key was used to secure the JWS. 

This MUST match the certificate id of the certificate selected in step 1.

The receiver SHOULD use this value to identify the certificate to be used for verifying the JWS.

Step 3: Form the Payload to be Signed

The JSON payload to be signed must have the following claims:

Claim

Required ?

Description

issMandatory

The issuer of the JWS.

This MUST match the dn of the certificate selected in step 1.

The payload to be signed is computed as:

payload = base64Encode(JOSEHeader) + "." + base64Encode(json)

Where:

JOSEHeader: is the header created in Step 2 and

json: is the message the original data to be sent

Step 4: Sign and Encode the Payload

The signed payload is computed as:

signedAndEncodedPayload = base64Encode(encrypt(privateKey, payload))

Where:

privateKey: is the private key selected in step 1

payload: is the payload computed in Step 3

encrypt: Is an encryption function that implements the `alg` identified in Step 2.

Step 5: Assemble the JWS

The JWS is computed as

JWS = payload + "." + signedAndEncodedPayload

Where:

payload: is the payload computed in Step 3

signedAndEncodedPayload: is the signed element computed in Step 5.

Implementation Guide

Overview

This provides an implementation perspective of the NZ Banking Data Security Profile aligned to the accepted NZ Banking Data APIs for Payments and Accounts Specifications.

Specified Behaviour

The implementation of both the Payments and Accounts API are based on the following known configurations:

Client Types

  • As per the OAuth 2.0 specification, the Confidential Client Type is illustrated for both Accounts and Payments API as it has the ability to maintain its own credentials.

Grant Types

OIDC Hybrid Flow (response_type=code id_token)

  • Both the Payments and Accounts APIs illustrate the use of request_type=code id_token for the OIDC Hybrid Flow implementation.    
  • The API Provider may optionally choose to return Refresh Tokens for the Hybrid Flow when issuing an Access Token

Client Credentials Grant Type (scope=third_party_client_credential)

  • The Client Credentials Grant Type is used across both Payments and Account APIs only when the Third Party requires an Access Token (on behalf of itself) in order to access a Payment or Accounts API resource e.g.

    Payments:

    POST /payments
    GET /payments/{PaymentId}

    Accounts: 

    POST /account-requests
    GET /account-requests/{AccountRequestId}
  • Only valid API scopes will be accepted when generating an Access Token (third_party_client_credential). 
  • Access tokens generated by a Client Credentials grant may not return any refresh tokens (as per the OAuth 2.0 specification)

Access Tokens

  • For the Payments and Accounts APIs, the Access Token must be obtained within a Secure, Server Side Context between the Third Party and the API Provider
  • Access Tokens must be validated by the Third Party as outlined within OIDC

Refresh Tokens

  • API Providers may optionally return a Refresh Token when an Authorization Request is successfully processed at the Token endpoint. The Hybrid flow supports the provisioning of Refresh Tokens.
  • The Accounts API implementation below cites an example for Third Parties requesting a Refresh Token to refresh an expired Access Token prior to invoking the /accounts resource.
  • Refresh Tokens must be validated as outlined in OIDC

ID Tokens

  • ID Tokens must be validated by the Third Party as outlined within OIDC
  • Third Parties must use the openbanking_intent_id claim to populate and retrieve the Intent Id (PaymentId for Payments API and AccountRequestId for the Accounts API) for any required validation.
  • The full set of claims that can be represented within an ID Token are documented in the Request Object and ID Token Section of the Security Profile.

Authorization Codes

  • Authorization Codes must be validated by the Third Party as outlined within OIDC

Unspecified Behaviour

The implementation of both the Payments and Accounts API are unspecified for the following configurations: 

Client Types

  • As per the OAuth 2.0 specification, the Public Client Type has not been illustrated for both Payments and Accounts APIs.

Grant Types

OIDC Hybrid Flow (response_type=code id_token token or response_type=code token)

  • Forces an Access Token to be returned from the API Provider Authorization endpoint (instead of a token endpoint). This is not illustrated in the Payments and Accounts API Specifications.

OIDC Implicit Flow (response_type=id_token token or response_type=id_token)

  • The Implicit Flow does not authenticate the Client that is invoking the request. This is not illustrated in the Payments and Accounts API Specifications.

Client Credentials Grant Type (scope=openid email profile address phone)

  • Requesting OIDC specific scopes or any unspecified scopes when using the Client Credentials grant. 

Validity Lengths

These are to be managed in the competitive space. Each API Provider's Authorization / Resource Server will be configured independently to comply with internal API Provider Security Policies and Guidelines. The Accounts and Payments API Specifications do not mandate validity lengths. 

Authorization Code

  •  OAuth 2.0 Specification suggests an Authorization Code should be short lived to a maximum of 10 minutes. Any codes exceeding this limit to be rejected.

ID Token

  • ID Token claims (exp and iat) determine its validity.

  • Returned with the Authorization Code when the Hybrid flow (code id_token) is initiated.

Access Token

  • The expires_in attribute returned by the Authorization Server when an Access Token is generated determines its validity.
  • Access Tokens are generally short lived, and where they expire, are then exchanged for another using a longer lived Refresh Token.
  • Refer to Section 16.18 of OIDC - Lifetimes of Access Tokens and Refresh Tokens.

Refresh Token

  • Refresh Tokens are generally longer lived in comparison to Access Tokens.
  • Refer to Section 16.18 of OIDC - Lifetimes of Access Tokens and Refresh Tokens.

Success Flows

Payment API Specification

The sequence diagram below highlights the OAuth 2.0 Client Credentials Grant and OIDC Hybrid flow that are used by the Payments API. 

Payment Initiation with Client Credentials Grant Type and OIDC Hybrid Flows
participant Customer
participant Third Party
participant API Provider Authorisation Server
participant API Provider Resource Server
   
autonumber 1
    
Customer -> Third Party: Establish TLS 1.2
    
note over Customer, API Provider Resource Server
Step 1: Request payment initiation
end note
Customer -> Third Party: Send payment initiation request
     
note over Customer, API Provider Resource Server
 Step 2: Setup single payment initiation
end note
    
    Third Party <-> API Provider Authorisation Server: Establish TLS 1.2 MA
    note left of Third Party
        Client Credentials Grant
    end note
    Third Party->API Provider Authorisation Server: POST /token (client authentication credentials, scope:third_party_client_credential)
    API Provider Authorisation Server->API Provider Authorisation Server: Validate client authentication credentials, scope
    API Provider Authorisation Server->API Provider Authorisation Server: Validate clientId matches client SSL cert
    API Provider Authorisation Server -> Third Party: HTTP 200 (OK) access-token (scope:third_party_client_credential)
        
    
    Third Party <-> API Provider Resource Server: Establish TLS 1.2 MA
    Third Party -> API Provider Resource Server: POST /payments (access-token - scope:third_party_client_credential)
    API Provider Resource Server->API Provider Resource Server: Validate access token
    API Provider Resource Server->API Provider Resource Server: Validate scope:third_party_client_credential
    API Provider Resource Server->API Provider Resource Server: Validate clientId matches client SSL cert
       
    API Provider Resource Server->API Provider Resource Server: Create new payment resource
    API Provider Resource Server->API Provider Resource Server: Bind PaymentId with ClientId
    API Provider Resource Server -> Third Party: HTTP 201 (Created),  PaymentId
    
    note right of Third Party
        Begin OIDC Hybrid Flow.
        See 6.1.  Passing a Request Object by Value
        See 5.5.  Requesting Claims using the "claims" Request Parameter
        The claims parameter must at least request:
             "id_token": {
       "openbanking_intent_id": {"value": PaymentId, "essential": true},
       "acr": {"essential": true}
      }
      The response object must be signed using the Third Party's private key.
    end note
    Third Party->Third Party: Persist PaymentId
    note right of Third Party
        The Third Party should store the PaymentId in a manner
        that it can be retrieved again later in the flow in Step 4.
           
        This could be stored in the user session (and retrieved using 'state'
        as a key) or the Customer could use some other unique identifier.
           
        This will be re-retrieved in [43].
           
    end note
    Third Party->Third Party: Create signed request object with requested Claims (PaymentId)
    Third Party -> Customer: HTTP 302 (Found); Location: /authorize,\nredirect-uri, clientId, state, nonce, scope=openid payments,\nresponse-type=code id_token,\nrequest=signed JWT request object - PaymentId)
    
note over Customer, API Provider Resource Server
 Step 3: Authorize consent
end note
    
Customer -> API Provider Authorisation Server: HTTP GET /authorize redirect-uri, clientId, state, nonce, scope=openid payments, response-type=code id_token,\nrequest=signed JWT request object - PaymentId
API Provider Authorisation Server->API Provider Authorisation Server: Validate clientid, scope
API Provider Authorisation Server->API Provider Authorisation Server: Validate redirect-uri for clientId
API Provider Authorisation Server->API Provider Authorisation Server: Validate JWT request claim -PaymentId
    note right of API Provider Authorisation Server
        Validate the request object by using the Third Party's public key.
        Third Party certificate will be identified using the kid claim
        in the JOSE header of the request object.
           
        Check that the PaymentId belongs to the ClientId that initiated the request.
    end note
API Provider Authorisation Server<->Customer: Authenticate (Login and consent page)
Customer <-> API Provider Authorisation Server: Select debtor account

API Provider Authorisation Server -> API Provider Resource Server: Update Payment Status to AcceptedCustomerProfile
API Provider Resource Server -> API Provider Authorisation Server: OK
note right of API Provider Authorisation Server
    Implementation of how the resource is updated is API Provider specific. (There is
    no standardised API for this)
end note
   
API Provider Authorisation Server->API Provider Authorisation Server: Generate authorization-code, id_token
note right of API Provider Authorisation Server
    id_token claims:{
    c_hash: 123,
    s_hash: 456
    }
    id_token must be signed using the API Provider's private key.
    The generation of c_hash is documented in OIDC: 3.3.2.11.  ID Token
    The generation of s_hash is in FAPI R/W spec: Section 5.1
    http://openid.net/specs/openid-financial-api-part-2-wd-02.html#introduction
end note
   
API Provider Authorisation Server -> Customer: HTTP 302 (Found); Location: redirect-uri (authorization-code, id_token, state)
Customer -> Third Party: HTTP GET redirect-uri (authorization-code, id_token, state)
Third Party->Third Party: Validate signature on id_token
note right of Third Party
    Validate the id_token by using the API Provider's public key.
    API Provider certificate will be identified using the kid claim
    in the JOSE header of the id_token
end note
Third Party->Third Party: Validate authorization-code using id_token (c_hash)
Third Party->Third Party: Validate state using id_token (s_hash)
Third Party->Third Party: Validate nonce using id_token
    
    
note right of Third Party:
    Exchange authorization-code for access token.
end note
Third Party <-> API Provider Authorisation Server: Establish TLS 1.2 MA
Third Party -> API Provider Authorisation Server: HTTP POST /token (client authentication credentials,\nauthorization-code, grant_type, redirect_uri)
    API Provider Authorisation Server->API Provider Authorisation Server: Validate clientId matches client SSL cert
    API Provider Authorisation Server->API Provider Authorisation Server: Validate client authentication credentials,\nauthorization-code
    API Provider Authorisation Server->API Provider Authorisation Server: Generate access-token
    API Provider Authorisation Server->API Provider Authorisation Server: Bind access-token to PaymentId
       
   
API Provider Authorisation Server -> Third Party: HTTP 200 (OK) access-token (scope:payments)
     
       
note over Customer, API Provider Resource Server
Step 4: Create payment submission
end note
Third Party <-> API Provider Resource Server: Establish TLS 1.2 MA
Third Party->Third Party: Retrieve PaymentId
note left of Third Party
    Retrieve the PaymentId that was issued in Step 2.
    The method for doing this will depend on how the Third Party persisted
    the payment id in [16]
       
end note
   
alt Validate PaymentId in  ID Token
    Third Party->Third Party: Decode / verify ID Token
    Third Party->Third Party: Read PaymentId from id_token claim
    Third Party->Third Party: Compare with PaymentId retrieved in [43]
else Validate PaymentId from UserInfo endpoint
    Third Party->API Provider Resource Server: GET /userInfo (access-token)
    API Provider Resource Server->API Provider Resource Server: Validate access-token matches client SSL cert
    API Provider Resource Server->API Provider Resource Server: Validate access-token
    API Provider Resource Server->Third Party: HTTP 200 (OK) - UserInfo claim - PaymentId
end
Third Party -> API Provider Resource Server: POST /payment-submissions (access-token - scope:payments) using PaymentId
    API Provider Resource Server->API Provider Resource Server: Validate access-token
    API Provider Resource Server->API Provider Resource Server: Validate access-token matches client SSL cert
    API Provider Resource Server->API Provider Resource Server: Validate scope:payments
    note right of API Provider Resource Server
        Check binding created in [38]
    end note
    API Provider Resource Server->API Provider Resource Server: Ensure access-token is bound to PaymentId
    API Provider Resource Server->API Provider Resource Server: Update payment status to AcceptedSettlementInProcess
API Provider Resource Server -> Third Party: HTTP 201 (Created), PaymentSubmissionId
     
note over Customer, API Provider Resource Server
Step 5: Get payment submission status
end note
     
opt
    Third Party <-> API Provider Resource Server: Establish TLS 1.2 MA
    alt Use active access token to retrieve payment status
        Third Party -> API Provider Resource Server: GET /payment-submissions/{PaymentSubmissionId} (access-token - scope:payments)
        API Provider Resource Server->API Provider Resource Server: Validate access-token
        API Provider Resource Server->API Provider Resource Server: Validate access-token matches client SSL cert
        API Provider Resource Server->API Provider Resource Server: Validate scope:payments
        API Provider Resource Server->Third Party: HTTP 200 (OK), payment-submissions resource
    end alt
end opt

Client Credentials Grant Type (OAuth 2.0)

Summary

This grant type is used by the Third Party in Step 2 to setup a single payment with the API Provider.

  1. The Third Party initiates an Authorization request using valid Client Credentials Grant type and scope(s)
  2. The API Provider Authorization Server validates the Client Authentication request from the Third Party and generates an Access Token response where the request is valid
  3. The Third Party uses the Access Token to create a new Payment resource against the API Provider Resource Server
  4. The API Provider Resource server responds with the PaymentId for the resource it has created
  5. The Client Credentials Grant may optionally be used by the Third Party in Step 5 to retrieve the status of a Payment

OIDC Hybrid Flow

Summary

  • The Hybrid flow is the recommendation from the NZ Banking Data Security Profile and the FAPI Specification for R/W. The Hybrid flow prevents IDP mixup attacks as documented by Nat Sakimura - Cut and Paste OAuth 2.0 Attack
  • This is initiated at the end of Step 2 by the Third Party after the PaymentId is generated by the API Provider and returned to the Third Party.
  • This is used in a redirect across the Customer and API Provider in Step 3 in order for the Customer to authorize consent with the API Provider - for the Third Party to proceed with the Payment.
  • This is used across the Third Party and API Provider in Step 4 by exchanging the Authorization Code for an Access Token in order to create the Payment-Submission resource.

Non-Normative HTTP Request and Response Examples

Step 1 - Request Payment Initiation

There are no Requests and Responses against the Payments API in this Step for the Customer, Third Party and API Provider.

Step 2 - Setup Single Payment Initiation

1. Third Party obtains an Access Token using a Client Credentials Grant Type. The scope third_party_client_credential must be used. When an Access Token expires, the Third Party will need to re-request for another Access Token using the same request below. 

Request : Client Credentials using private_key_jwt

Response : Client Credentials

POST /as/token.oauth2 HTTP/1.1
Host: https://authn.alphabank.com
Content-Type: application/x-www-form-urlencoded
Accept: application/json
grant_type=client_credentials
&scope=third_party_client_credential
&client_assertion_type=
    urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRw
czovL2p3dC1pZHAuZXhhbXBsZS5jb20iLCJzdWIiOiJtYWlsdG86bWlrZUBleGFtcGxlLmN
vbSIsIm5iZiI6MTQ5OTE4MzYwMSwiZXhwIjoxNDk5MTg3MjAxLCJpYXQiOjE0OTkxODM2MD
EsImp0aSI6ImlkMTIzNDU2IiwidHlwIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9yZWdpc3Rlc
iJ9.SAxPMaJK_wYl_W2idTQASjiEZ4UoI7-P2SbmnHKr6LvP8ZJZX6JlnpK_xClJswAni1T
p1UnHJslc08JrexctaeEIBrqwHG18iBcWKjhHK2Tv5m4nbTsSi1MFQOlMUTRFq3_LQiHqV2
M8Hf1v9q9YaQqxDa4MK0asDUtE_zYMHz8kKDb-jj-Vh4mVDeM4_FPiffd2C5ckjkrZBNOK0
01Xktm7xTqX6fk56KTrejeA4x6D_1ygJcGfjZCv6Knki7Jl-6MfwUKb9ZoZ9LiwHf5lLXPuy
_QrOyM0pONWKj9K4Mj7I4GPGvzyVqpaZUgjcOaZY_rlu_p9tnSlE781dDLuw

Non-Base64 JWT client_assertion
{
	"alg": "PS256",
	"kid": "12345",
	"typ": "JWT"
}
.
{
	"iss": "s6BhdRkqt3",
	"sub": "s6BhdRkqt3",
	"exp": 1499187201,
	"iat": 1499183601,
	"jti": "id123456",
	"aud": "https://authn.alphabank.com/as/token.oauth2"
}
.
<<signature>>
HTTP/1.1 200 OK
Content-Length: 1103
Content-Type: application/json
Date: Mon, 26 Jun 2017 15:18:28 GMT

{
	"access_token": "2YotnFZFEjr1zCsicMWpAA",
	"expires_in": 3600,
	"token_type": "bearer",
	"scope": "third_party_client_credential"
}


2. Third Party uses the Access Token (with third_party_client_credential scope) from the API Provider to invoke the Payments API. 

Request : Payments APIResponse : Payments API
POST /payments HTTP/1.1
Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA
x-idempotency-key: FRESCO.21302.GFX.20
x-fapi-customer-last-logged-time: 2017-06-13T11:36:09
x-fapi-customer-ip-address: 104.25.212.99
x-fapi-interaction-id: 93bac548-d2de-4546-b106-880a5018460d
Content-Type: application/json
Accept: application/json
 
{
	"Data": {
		"Initiation": {
			"InstructionIdentification": "ACME412",
			"EndToEndIdentification": "FRESCO.21302.GFX.20",
			"InstructedAmount": {
				"Amount": "165.88",
				"Currency": "NZD"
			},
			"CreditorAccount": {
				"SchemeName": "BECSElectronicCredit",
				"Identification": "08080021325698",
				"Name": "ACME Inc",
				"SecondaryIdentification": "0002"
			},
			"RemittanceInformation": {
				"Reference": {
					"CreditorName": "The Creditor",
					"CreditorReference": {
						"Particulars": "CreditorPart",
						"Code": "CreditorCode",
						"Reference": "CreditorRef"
					}
				}
			}
		}
	},
	"Risk": {
		"PaymentContextCode": "EcommerceGoods",
		"MerchantCategoryCode": "5967",
		"MerchantCustomerIdentification": "053598653254",
		"DeliveryAddress": {
			"AddressLine": [
				"Flat 7",
				"Acacia Lodge"
			],
			"StreetName": "Acacia Avenue",
			"BuildingNumber": "27",
			"PostCode": "1010",
			"TownName": "Auckland",
			"CountySubDivision": [
				"Auckland Central"
			],
			"Country": "NZ"
		}
	}
}
HTTP/1.1 201 Created
x-fapi-interaction-id: 93bac548-d2de-4546-b106-880a5018460d
Content-Type: application/json
 
{
	"Data": {
		"PaymentId": "58923",
		"Status": "AcceptedTechnicalValidation",
		"CreationDateTime": "2017-06-05T15:15:13+00:00",
		"Initiation": {
			"InstructionIdentification": "ACME412",
			"EndToEndIdentification": "FRESCO.21302.GFX.20",
			"InstructedAmount": {
				"Amount": "165.88",
				"Currency": "NZD"
			},
			"CreditorAccount": {
				"SchemeName": "BECSElectronicCredit",
				"Identification": "08080021325698",
				"Name": "ACME Inc",
				"SecondaryIdentification": "0002"
			},
			"RemittanceInformation": {
				"Reference": {
					"CreditorName": "The Creditor",
					"CreditorReference": {
						"Particulars": "CreditorPart",
						"Code": "CreditorCode",
						"Reference": "CreditorRef"
					}
				}
			}
		}
	},
	"Risk": {
		"PaymentContextCode": "EcommerceGoods",
		"MerchantCategoryCode": "5967",
		"MerchantCustomerIdentification": "053598653254",
		"DeliveryAddress": {
			"AddressLine": [
				"Flat 7",
				"Acacia Lodge"
			],
			"StreetName": "Acacia Avenue",
			"BuildingNumber": "27",
			"PostCode": "1010",
			"TownName": "Auckland",
			"CountySubDivision": [
				"Auckland Central"
			],
			"Country": "NZ"
		}
	},
	"Links": {
		"Self": "https://api.alphabank.com/open-banking/v1.0/payments/58923"
	},
	"Meta": {}
}


Step 3 - Authorize Consent

1. Third Party receives a PaymentId from the API Provider. The Third Party then creates an Authorization request (using a signed JWT Request containing the PaymentID as a claim) for the Customer to consent to the Payment directly with their API Provider. The request is an OIDC Hybrid flow (requesting for code and id_token)

Request : OIDC Hybrid Flow

Response : OIDC Hybrid Flow

  • Sourced from the NZ Banking Data Security Profile Request Object section
Base 64 Encoded Example
GET /authorize?
response_type=code id_token
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&scope=openid payments
&nonce=n-0S6_WzA2Mj
&redirect_uri=https://api.mytpp.com/cb
&request=CJleHAiOjE0OTUxOTk1ODd.....JjVqsDuushgpwp0E.5leGFtcGxlI
iwianRpIjoiM....JleHAiOjE0.olnx_YKAm2J1rbpOP8wGhi1BDNHJjVqsDuushgpwp0E


Non-Base64 encoded example of the request parameter object
{
	"alg": "PS256",
	"kid": "GxlIiwianVqsDuushgjE0OTUxOTk"
}
.
{
	"iss": "https://api.alphabank.com",
	"aud": "s6BhdRkqt3",
	"response_type": "code id_token",
	"client_id": "s6BhdRkqt3",
	"redirect_uri": "https://api.mytpp.com/cb",
	"scope": "openid payments accounts",
	"state": "af0ifjsldkj",
	"nonce": "n-0S6_WzA2Mj",
	"max_age": 86400,
	"claims": {
		"userinfo": {
			"openbanking_intent_id": {
				"value": "urn:alphabank:intent:58923",
				"essential": true
			}
		},
		"id_token": {
			"openbanking_intent_id": {
				"value": "urn:alphabank:intent:58923",
				"essential": true
			},
			"acr": {
				"essential": true,
				"values": ["urn:openbanking:nz:sca",
					"urn:openbanking:nz:ca"
				]
			}
		}
	}
}
.
<<signature>>
  • After the Customer has consented directly with the API Provider via their web application (and confirmed the Debtor account) the API Provider validates the Authorization request and generates an Auth Code and ID Token
HTTP/1.1 302 Found
  Location: https://api.mytpp.com/cb#
    code=SplxlOBeZQQYbYS6WxSbIA
    &id_token=eyJ0 ... NiJ9.eyJ1c ... I6IjIifX0.DeWt4Qu ... ZXso
    &state=af0ifjsldkj


2. The Customer is then redirected to the Third Party. The Third Party will now possess the Authorization Code and ID Token from the API Provider. Note at this point, there is no Access Token. The Third Party will now introspect the ID Token and use it as a detached signature to check:

  • The hash of the Authorization Code to prove it hasn't been tampered with during redirect (comparing the hash value against the c_hash attribute in ID Token)
  • The hash of the State to prove it hasn't been tampered with during redirect (comparing the state hash value against the s_hash attribute in the ID Token)
Example: ID Token

Sourced from the NZ Banking Data Security Profile Request Object section

{
	"alg": "PS256",
	"kid": "12345",
	"typ": "JWT"
}
. 
{
	"iss": "https://api.alphabank.com",
	"iat": 1234569795,
	"sub": "urn:alphabank:payment:58923",
	"acr": "urn:openbanking:nz:ca",
	"openbanking_intent_id": "urn:alphabank-intent-58923",
	"aud": "s6BhdRkqt3",
	"nonce": "n-0S6_WzA2Mj",
	"exp": 1311281970,
	"s_hash": "76sa5dd",
	"c_hash": "asd097d"
}
.
<<signature>> 


3. Once the state and code validations have been confirmed as successful by use of the ID token, the Third Party will proceed to obtain an Access Token from the API Provider using the Authorization Code they now possess. The Third Party will present its Authorization Code together with the private_key_jwt. The Access Token is required by the Third Party in order to submit the Payment on behalf of the Customer. The payments scope should already be associated with the Authorization Code generated in the previous step.

Request : Access Token Request using Authorization Code and private_key_jwtResponse : Access Token
POST /as/token.oauth2 HTTP/1.1
Host: https://authn.alphabank.com
Content-Type: application/x-www-form-urlencoded
Accept: application/json
grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https://api.mytpp.com/cb
&client_assertion_type=
    urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRw
czovL2p3dC1pZHAuZXhhbXBsZS5jb20iLCJzdWIiOiJtYWlsdG86bWlrZUBleGFtcGxlLmN
vbSIsIm5iZiI6MTQ5OTE4MzYwMSwiZXhwIjoxNDk5MTg3MjAxLCJpYXQiOjE0OTkxODM2MD
EsImp0aSI6ImlkMTIzNDU2IiwidHlwIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9yZWdpc3Rlc
iJ9.SAxPMaJK_wYl_W2idTQASjiEZ4UoI7-P2SbmnHKr6LvP8ZJZX6JlnpK_xClJswAni1T
p1UnHJslc08JrexctaeEIBrqwHG18iBcWKjhHK2Tv5m4nbTsSi1MFQOlMUTRFq3_LQiHqV2
M8Hf1v9q9YaQqxDa4MK0asDUtE_zYMHz8kKDb-jj-Vh4mVDeM4_FPiffd2C5ckjkrZBNOK0
01Xktm7xTqX6fk56KTrejeA4x6D_1ygJcGfjZCv6Knki7Jl-6MfwUKb9ZoZ9LiwHf5lLXPuy
_QrOyM0pONWKj9K4Mj7I4GPGvzyVqpaZUgjcOaZY_rlu_p9tnSlE781dDLuw
Non-Base64 JWT client_assertion
{
	"alg": "PS256",
	"kid": "12345",
	"typ": "JWT"
}
.
{
	"iss": "s6BhdRkqt3",
	"sub": "s6BhdRkqt3",
	"exp": 1499187201,
	"iat": 1499183601,
	"jti": "id123456",
	"aud": "https://authn.alphabank.com/as/token.oauth2"
}
.
<<signature>>
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
	"access_token": "SlAV32hkKG",
	"token_type": "Bearer",
	"expires_in": 3600
}


Step 4 - Create Payment-Submission

1. The Third Party has an Access Token which can be used to Create a Payment-Submission (Step 4). The Third Party must obtain the PaymentId (Intent Id) so that the Payment request is associated with the correct PaymentId. This can be sourced from either:

  1. The PaymentId claim from the signed ID Token (default). The Third Party will need to decode the ID Token JWT and locate the claim attribute associated with the PaymentId.
  2. The PaymentId claim from the /userInfo resource endpoint of the API Provider (optional for API Providers to implement) .

The example below provides an illustration of the Third Party requesting the /userInfo endpoint of the API Provider in order to get the PaymentID (returned as openbanking_intent_id)

Request : UserInfoResponse : UserInfo
GET /userinfo HTTP/1.1
  Host: api.alphabank.com
  Authorization: Bearer SlAV32hkKG
HTTP/1.1 200 OK
Content-Type: application/json

{
	"sub": "Customer User Id",
	"openbanking_intent_id": "urn:alphabank-intent-58923",
	"name": "Jane Doe",
	"given_name": "Jane",
	"family_name": "Doe",
	"preferred_username": "Jane Doe",
	"email": "jane.doe@example.com",
	"picture": "http://example.com/janedoe/me.jpg"
}

2. The Third Party can now invoke the /payment-submissions endpoint to commit the Payment using the Access Token and PaymentId in the payload of the request. This example is sourced from the Payment Initiation API Specification

Request : payment-submissionsResponse : payment-submissions
POST /payment-submissions HTTP/1.1
Authorization: Bearer SlAV32hkKG
x-idempotency-key: FRESNO.1317.GFX.22
x-fapi-customer-last-logged-time: 2017-06-13T11:36:09
x-fapi-customer-ip-address: 104.25.212.99
x-fapi-interaction-id: 93bac548-d2de-4546-b106-880a5018460d
Content-Type: application/json
Accept: application/json
 
{
	"Data": {
		"PaymentId": "58923",
		"Initiation": {
			"InstructionIdentification": "ACME412",
			"EndToEndIdentification": "FRESCO.21302.GFX.20",
			"InstructedAmount": {
				"Amount": "165.88",
				"Currency": "NZD"
			},
			"CreditorAccount": {
				"SchemeName": "BECSElectronicCredit",
				"Identification": "08080021325698",
				"Name": "ACME Inc",
				"SecondaryIdentification": "0002"
			},
			"RemittanceInformation": {
				"Reference": {
					"CreditorName": "The Creditor",
					"CreditorReference": {
						"Particulars": "CreditorPart",
						"Code": "CreditorCode",
						"Reference": "CreditorRef"
					}
				}
			}
		}
	},
	"Risk": {
		"PaymentContextCode": "EcommerceGoods",
		"MerchantCategoryCode": "5967",
		"MerchantCustomerIdentification": "053598653254",
		"DeliveryAddress": {
			"AddressLine": [
				"Flat 7",
				"Acacia Lodge"
			],
			"StreetName": "Acacia Avenue",
			"BuildingNumber": "27",
			"PostCode": "1010",
			"TownName": "Auckland",
			"CountySubDivision": [
				"Auckland Central"
			],
			"Country": "NZ"
		}
	}
}
HTTP/1.1 201 Created
x-fapi-interaction-id: 93bac548-d2de-4546-b106-880a5018460d
Content-Type: application/json
 
{
	"Data": {
		"PaymentSubmissionId": "58923-001",
		"PaymentId": "58923",
		"Status": "AcceptedSettlementInProcess",
		"CreationDateTime": "2017-06-05T15:15:22+00:00",
		"Initiation": {
			"InstructionIdentification": "ACME412",
			"EndToEndIdentification": "FRESCO.21302.GFX.20",
			"InstructedAmount": {
				"Amount": "165.88",
				"Currency": "NZD"
			},
			"CreditorAccount": {
				"SchemeName": "BECSElectronicCredit",
				"Identification": "08080021325698",
				"Name": "ACME Inc",
				"SecondaryIdentification": "0002"
			},
			"RemittanceInformation": {
				"Reference": {
					"CreditorName": "The Creditor",
					"CreditorReference": {
						"Particulars": "CreditorPart",
						"Code": "CreditorCode",
						"Reference": "CreditorRef"
					}
				}
			}
		}
	},
	"Links": {
		"Self": "https://api.alphabank.com/open-banking/v1.0/payment-submissions/58923-001"
	},
	"Meta": {}
}

Step 5 - Get Payment-Submission Status

1. The Third Party can query for the status of a Payment-Submission by invoking the /payment-submissions using the known PaymentSubmissionId. This can use an existing access token with payments scope or the Third Party can obtain a fresh access token by replaying the client credentials grant request as per Step 2 - Setup Single Payment Initiation.

Request: payment-submissions/{PaymentSubmissionId}Response: payment-submissions
GET /payment-submissions/58923-001 HTTP/1.1
Authorization: Bearer SlAV32hkKG
x-fapi-customer-last-logged-time: 2017-06-13T11:36:09
x-fapi-customer-ip-address: 104.25.212.99
x-fapi-interaction-id: 93bac548-d2de-4546-b106-880a5018460d
Accept: application/json
HTTP/1.1 200 OK
x-fapi-interaction-id: 93bac548-d2de-4546-b106-880a5018460d
Content-Type: application/json
 
{
	"Data": {
		"PaymentSubmissionId": "58923-001",
		"PaymentId": "58923",
		"Status": "AcceptedSettlementInProcess",
		"CreationDateTime": "2017-06-05T15:15:22+00:00",
		"Initiation": {
			"InstructionIdentification": "ACME412",
			"EndToEndIdentification": "FRESCO.21302.GFX.20",
			"InstructedAmount": {
				"Amount": "165.88",
				"Currency": "NZD"
			},
			"CreditorAccount": {
				"SchemeName": "BECSElectronicCredit",
				"Identification": "08080021325698",
				"Name": "ACME Inc",
				"SecondaryIdentification": "0002"
			},
			"RemittanceInformation": {
				"Reference": {
					"CreditorName": "The Creditor",
					"CreditorReference": {
						"Particulars": "CreditorPart",
						"Code": "CreditorCode",
						"Reference": "CreditorRef"
					}
				}
			}
		}
	},
	"Links": {
		"Self": "https://api.alphabank.com/open-banking/v1.0/payment-submissions/58923-001"
	},
	"Meta": {}
}

2. A Third Party can also optionally query for the status of a Payment resource by invoking /payments/{PaymentId}. This can use an existing access token with third_party_client_credential scope or the Third Party can obtain a fresh access token by replaying the client credentials grant request as per Step 2 - Setup Single Payment Initiation.

Account API Specification

The sequence diagram below highlights the OAuth 2.0 Client Credentials Grant and OIDC Hybrid flow that are used by the Account and Transactions API.

Account and Transactions API with Client Credentials Grant and OIDC Hybrid flow
participant Customer
participant Third Party
participant API Provider Authorisation Server
participant API Provider Resource Server
autonumber 1
      
Customer -> Third Party: Establish TLS 1.2
    
      
note over Customer, API Provider Resource Server
    Step 1: Request account information
end note
Customer -> Third Party: Get account/transaction information
     
note over Customer, API Provider Resource Server
    Step 2: Setup account request
end note
Third Party <-> API Provider Authorisation Server: Establish TLS 1.2 MA
    
    note left of Third Party
        Client Credentials Grant
    end note
    Third Party->API Provider Authorisation Server: POST /token (client authentication credentials, scope:third_party_client_credential)
    API Provider Authorisation Server->API Provider Authorisation Server: Validate client authentication credentials, scope
    API Provider Authorisation Server->API Provider Authorisation Server: Validate clientId matches client SSL cert
    API Provider Authorisation Server -> Third Party: HTTP 200 (OK) access-token (scope:third_party_client_credential)
    
    
Third Party <-> API Provider Resource Server: Establish TLS 1.2 MA
Third Party -> API Provider Resource Server: POST /account-requests (access-token - scope:third_party_client_credential)
    API Provider Resource Server->API Provider Resource Server: Validate access token
    API Provider Resource Server->API Provider Resource Server: Validate scope:third_party_client_credential
    API Provider Resource Server->API Provider Resource Server: Validate clientId matches client SSL cert
    API Provider Resource Server->API Provider Resource Server: Create new account-request resource
    API Provider Resource Server->API Provider Resource Server: Bind AccountRequestId with ClientId
    
API Provider Resource Server -> Third Party: HTTP 201 (Created), AccountRequestId
    note right of Third Party
        Begin OIDC Hybrid Flow.
        See 6.1.  Passing a Request Object by Value
        See 5.5.  Requesting Claims using the "claims" Request Parameter
        The claims parameter must at least request:
             "id_token": {
       "openbanking_intent_id": {"value": AccountRequestId, "essential": true},
       "acr": {"essential": true}
      }
      The response object must be signed using the PISP's private key.
    end note
    Third Party->Third Party: Persist AccountRequestId
      note right of Third Party
        The Third Party should store the AccountRequestId in a manner
        that it can be retrieved again later in the flow in Step 4.
             
        This could be stored in the user session (and retrieved using 'state'
        as a key) or the Customer could use some other unique identifier.
             
        This can be re-retrieved in [81] and [96].
             
    end note
    
    Third Party->Third Party: Create signed request object with requested Claims (AccountRequestId)
        
    
    
    Third Party -> Customer: HTTP 302 (Found); Location: /authorize,\nredirect-uri, clientId, state, nonce, scope=openid accounts,\nresponse-type=code id_token,\nrequest=signed JWT request object - AccountRequestId)
    
     
note over Customer, API Provider Resource Server
Step 3: Authorise consent
end note
Customer -> API Provider Authorisation Server: HTTP GET /authorize redirect-uri, clientId, state, nonce, scope=openid accounts, response-type=code id_token,\nrequest=signed JWT request object - AccountRequestId
API Provider Authorisation Server->API Provider Authorisation Server: Validate clientid, scope
API Provider Authorisation Server->API Provider Authorisation Server: Validate redirect-uri for clientId
API Provider Authorisation Server->API Provider Authorisation Server: Validate JWT request claim -AccountRequestId
note right of API Provider Authorisation Server
        Validate the request object by using the Third Party's public key.
        PISP certificate will be identified using the kid claim
        in the JOSE header of the request object.
             
        Check that the AccountRequestId belongs to the ClientId that initiated the request.
    end note
    
Customer <-> API Provider Authorisation Server: Authenticate (Login and Consent Page)
Customer <-> API Provider Authorisation Server: Select Accounts

API Provider Authorisation Server->API Provider Resource Server: Update account-requests Status to Authorised
API Provider Resource Server->API Provider Authorisation Server:OK
note right of API Provider Authorisation Server
    Implementation of how the resource is updated is API Provider specific (There
    is no standardised API for this)
end note

API Provider Authorisation Server->API Provider Authorisation Server: Generate authorization-code, id_token
note right of API Provider Authorisation Server
    id_token claims:{
    c_hash: 123,
    s_hash: 456
    }
    id_token must be signed using the API Provider's private key.
    The generation of c_hash is documented in OIDC: 3.3.2.11.  ID Token
    The generation of s_hash is in FAPI R/W spec: Section 5.1
    http://openid.net/specs/openid-financial-api-part-2-wd-02.html#introduction
end note
API Provider Authorisation Server-> API Provider Authorisation Server: Bind selected Accounts to AccountRequestId
API Provider Authorisation Server -> Customer: HTTP 302 (Found); Location: redirect-uri (authorization-code, id_token, state)
Customer -> Third Party: HTTP GET redirect-uri (authorization-code, id_token, state)
Third Party->Third Party: Validate signature on id_token
note right of Third Party
    Validate the id_token by using the API Provider's public key.
    API Provider certificate will be identified using the kid claim
    in the JOSE header of the id_token
end note
Third Party->Third Party: Validate authorization-code using id_token (c_hash)
Third Party->Third Party: Validate state using id_token (s_hash)
Third Party->Third Party: Validate nonce using id_token
note right of Third Party:
    Exchange authorization-code for access token.
end note
    
    
    
Third Party <-> API Provider Authorisation Server: Establish TLS 1.2 MA
Third Party -> API Provider Authorisation Server: HTTP POST /token (client authentication credentials,\nauthorization-code, grant_type, redirect_uri)
    API Provider Authorisation Server->API Provider Authorisation Server: Validate clientId matches client SSL cert
    API Provider Authorisation Server->API Provider Authorisation Server: Validate client authentication credentials,\nauthorization-code
    API Provider Authorisation Server->API Provider Authorisation Server: Generate access-token
    API Provider Authorisation Server->API Provider Authorisation Server: Bind access-token to AccountRequestId
    note right of API Provider Authorisation Server
        Implies an association of Accounts to access-token
    end note
alt Access Token
    API Provider Authorisation Server -> Third Party: HTTP 200 (OK) access-token (scope:accounts)
  
else Optional Refresh Token
    API Provider Authorisation Server->API Provider Authorisation Server: Generate Refresh Token
    API Provider Authorisation Server -> Third Party: HTTP 200 (OK) access-token, refresh-token (scope:accounts)
  
end
     
      
note over Customer, API Provider Resource Server
Step 4: Request data
end note
Third Party <-> API Provider Resource Server: Establish TLS 1.2 MA
Third Party<->Third Party: Retrieve access-token
note left of Third Party
    Retrieve the access-token that was issued in Step [42].
    The access-token is  linked with consented Accounts
    from Steps [27] and [39]
end note
  
alt Valid Access Token
    Third Party -> API Provider Resource Server: GET /accounts (access-token - scope:accounts)
    API Provider Resource Server->API Provider Resource Server: Validate access-token
    API Provider Resource Server->API Provider Resource Server: Validate access-token matches client SSL cert
    API Provider Resource Server->API Provider Resource Server: Validate scope:accounts
    API Provider Resource Server -> Third Party: HTTP 200 (OK), List of accounts containing AccountId(s)
    Third Party -> API Provider Resource Server: GET /accounts/{AccountId}/transactions (access-token - scope:accounts)
    API Provider Resource Server->API Provider Resource Server: Validate access-token
    API Provider Resource Server->API Provider Resource Server: Validate access-token matches client SSL cert
 
    API Provider Resource Server->API Provider Resource Server: Validate scope:accounts
    API Provider Resource Server->API Provider Resource Server: Validate access-token bound to AccountId
    API Provider Resource Server -> Third Party: HTTP 200 (OK), List of transactions
else Expired Access Token
    Third Party->Third Party: Retrieve Refresh Token from [44]
    Third Party->API Provider Authorisation Server:HTTP POST /token (client authentication credentials,\ngrant_type=refresh_token,refresh_token=[58],\nscope=openid accounts)
    API Provider Authorisation Server->API Provider Authorisation Server: Validate clientId matches client SSL cert
    API Provider Authorisation Server->API Provider Authorisation Server: Validate client authentication credentials,\refresh_token
    API Provider Authorisation Server->API Provider Authorisation Server: Generate Access Token and Refresh Token
    API Provider Authorisation Server -> Third Party: HTTP 200 (OK) access-token, refresh-token (scope:accounts)
    Third Party -> API Provider Resource Server: GET /accounts (access-token - scope:accounts)
    API Provider Resource Server->API Provider Resource Server: Validate access-token
    API Provider Resource Server->API Provider Resource Server: Validate access-token matches client SSL cert
    API Provider Resource Server->API Provider Resource Server: Validate scope:accounts
    API Provider Resource Server -> Third Party: HTTP 200 (OK), List of accounts containing AccountId(s)
    Third Party -> API Provider Resource Server: GET /accounts/{AccountId}/transactions (access-token - scope:accounts)
    API Provider Resource Server->API Provider Resource Server: Validate access-token
    API Provider Resource Server->API Provider Resource Server: Validate access-token matches client SSL cert
    API Provider Resource Server->API Provider Resource Server: Validate scope:accounts
    API Provider Resource Server->API Provider Resource Server: Validate access-token bound to AccountId
    API Provider Resource Server -> Third Party: HTTP 200 (OK), List of transactions
else Account Request - Get Status
Third Party <-> API Provider Authorisation Server: Establish TLS 1.2 MA
    
    note left of Third Party
        Client Credentials Grant
    end note
    Third Party->API Provider Authorisation Server: POST /token (client authentication credentials, scope:accounts)
    API Provider Authorisation Server->API Provider Authorisation Server: Validate client authentication credentials, scope
    API Provider Authorisation Server->API Provider Authorisation Server: Validate clientId matches client SSL cert
    API Provider Authorisation Server -> Third Party: HTTP 200 (OK) access-token (scope:accounts)
    
    
    Third Party <-> API Provider Resource Server: Establish TLS 1.2 MA
    Third Party->Third Party: Retrieve AccountRequestId from [16]
    Third Party -> API Provider Resource Server: GET /account-requests/{AccountRequestId} (access-token - scope:third_party_client_credential)
        API Provider Resource Server->API Provider Resource Server: Validate access token
        API Provider Resource Server->API Provider Resource Server: Validate scope:third_party_client_credential
        API Provider Resource Server->API Provider Resource Server: Validate clientId matches client SSL cert
        API Provider Resource Server->API Provider Resource Server: Lookup AccountRequestId resource
     
    API Provider Resource Server -> Third Party: HTTP 200 (OK), AccountRequest Status
 
else Account Request- Customer removes consent at a later point in time with the Third Party
Customer -> Third Party: Establish TLS 1.2
Customer -> Third Party: Remove Consent
 
Third Party <-> API Provider Authorisation Server: Establish TLS 1.2 MA
    
    note left of Third Party
        Client Credentials Grant
    end note
    Third Party->API Provider Authorisation Server: POST /token (client authentication credentials, scope:third_party_client_credential)
    API Provider Authorisation Server->API Provider Authorisation Server: Validate client authentication credentials, scope
    API Provider Authorisation Server->API Provider Authorisation Server: Validate clientId matches client SSL cert
    API Provider Authorisation Server -> Third Party: HTTP 200 (OK) access-token (scope:third_party_client_credential)
    
    
    Third Party <-> API Provider Resource Server: Establish TLS 1.2 MA
    Third Party->Third Party: Retrieve AccountRequestId from [16]
    Third Party -> API Provider Resource Server: DELETE /account-requests/{AccountRequestId} (access-token - scope:third_party_client_credential)
        API Provider Resource Server->API Provider Resource Server: Validate access token
        API Provider Resource Server->API Provider Resource Server: Validate scope:third_party_client_credential
        API Provider Resource Server->API Provider Resource Server: Validate clientId matches client SSL cert
        API Provider Resource Server->API Provider Resource Server: Delete AccountRequestId resource
     
    API Provider Resource Server -> Third Party: HTTP 204 (No Content)
    Third Party->Customer: Consent Removed
end

Client Credentials Grant Type (OAuth 2.0)

Summary

This grant type is used by the Third Party in Step 2 to register an intent for the Customer to allow the Third Party to retrieve their Account information from an API Provider.

  1. The Third Party initiates an Authorization request using valid Client Credentials Grant type and scope(s)
  2. The API Provider Authorization Server validates the Client Authentication request from the Third Party and generates an Access Token response where the request is valid
  3. The Third Party uses the Access Token to create a new Account Request resource against the API Provider Resource Server
  4. The API Provider Resource server responds with the AccountRequestId representing the resource it has created. 

OIDC Hybrid Flow

Summary

  • This is initiated at the end of Step 2 by the Third Party after the AccountRequestId is generated by the API Provider and returned to the Third Party.
  • This is used in a redirect across the Customer and API Provider in Step 3 in order for the Customer to authorize consent with the API Provider - for the Third Party to proceed with the requesting Account information.
  • This is used across the Third Party and API Provider in Step 4 by swapping the Authorization Code for an Access Token in order to retrieve Customer Account information.

Non-Normative HTTP Request and Response Examples

Step 1 - Request Account Information

There are no Requests and Responses against the Account Information API in this Step for the Customer, Third Party and API Provider.

Step 2 - Setup Account Request

1. Third Party obtains an Access Token using a Client Credentials Grant Type. The scope third_party_client_credential must be used. When an Access Token expires, the Third Party will need to re-request for another Access Token using the same request below.

Request : Client Credentials using private_key_jwt

Response : Client Credentials

POST  /as/token.oauth2 HTTP/1.1
Host: https://authn.alphabank.com
Content-Type: application/x-www-form-urlencoded
Accept: application/json
grant_type=client_credentials
&scope=third_party_client_credential
&client-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRw
czovL2p3dC1pZHAuZXhhbXBsZS5jb20iLCJzdWIiOiJtYWlsdG86bWlrZUBleGFtcGxlLmN
vbSIsIm5iZiI6MTQ5OTE4MzYwMSwiZXhwIjoxNDk5MTg3MjAxLCJpYXQiOjE0OTkxODM2MD
EsImp0aSI6ImlkMTIzNDU2IiwidHlwIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9yZWdpc3Rlc
iJ9.SAxPMaJK_wYl_W2idTQASjiEZ4UoI7-P2SbmnHKr6LvP8ZJZX6JlnpK_xClJswAni1T
p1UnHJslc08JrexctaeEIBrqwHG18iBcWKjhHK2Tv5m4nbTsSi1MFQOlMUTRFq3_LQiHqV2
M8Hf1v9q9YaQqxDa4MK0asDUtE_zYMHz8kKDb-jj-Vh4mVDeM4_FPiffd2C5ckjkrZBNOK0
01Xktm7xTqX6fk56KTrejeA4x6D_1ygJcGfjZCv6Knki7Jl-6MfwUKb9ZoZ9LiwHf5lLXPuy
_QrOyM0pONWKj9K4Mj7I4GPGvzyVqpaZUgjcOaZY_rlu_p9tnSlE781dDLuw

Non-Base64 JWT client_assertion
{
	"alg": "PS256",
	"typ": "JWT",
	"kid": "1234adsf"
}
.
{
	"iss": "s6BhdRkqt3",
	"sub": "s6BhdRkqt3",
	"exp": 1499187201,
	"iat": 1499183601,
	"jti": "id123456",
	"aud": "https://authn.alphabank.com/as/token.oauth2"
}
.
<<signature>>
HTTP/1.1 200 OK
Content-Length: 1103
Content-Type: application/json
Date: Mon, 26 Jun 2017 15:18:28 GMT

{
	"access_token": "2YotnFZFEjr1zCsicMWpAA",
	"expires_in": 3600,
	"token_type": "bearer",
	"scope": "third_party_client_credential"
}


2. Third Party uses the Access Token (with third_party_client_credential scope) from the API Provider to invoke the Accounts API.  

Request: Accounts APIResponse: Accounts API
POST /account-requests HTTP/1.1
Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA
x-fapi-customer-last-logged-time: 2017-06-13T11:36:09
x-fapi-customer-ip-address: 104.25.212.99
x-fapi-interaction-id: 93bac548-d2de-4546-b106-880a5018460d
Content-Type: application/json
Accept: application/json

{
	"Data": {
		"Permissions": [
			"ReadAccountsDetail",
			"ReadBalances",
			"ReadBeneficiariesDetail",
			"ReadDirectDebits",
			"ReadStandingOrdersDetail",
			"ReadTransactionsCredits",
			"ReadTransactionsDebits",
			"ReadTransactionsDetail"
		],
		"ExpirationDateTime": "2017-05-02T00:00:00+00:00",
		"TransactionFromDateTime": "2017-05-03T00:00:00+00:00",
		"TransactionToDateTime": "2017-12-03T00:00:00+00:00"
	},
	"Risk": {}
}
HTTP/1.1 201 Created
x-fapi-interaction-id: 93bac548-d2de-4546-b106-880a5018460d
Content-Type: application/json
 
{
	"Data": {
		"AccountRequestId": "88379",
		"Status": "AwaitingAuthorisation",
		"CreationDateTime": "2017-05-02T00:00:00+00:00",
		"Permissions": [
			"ReadAccountsDetail",
			"ReadBalances",
			"ReadBeneficiariesDetail",
			"ReadDirectDebits",
			"ReadStandingOrdersDetail",
			"ReadTransactionsCredits",
			"ReadTransactionsDebits",
			"ReadTransactionsDetail"
		],
		"ExpirationDateTime": "2017-08-02T00:00:00+00:00",
		"TransactionFromDateTime": "2017-05-03T00:00:00+00:00",
		"TransactionToDateTime": "2017-12-03T00:00:00+00:00"
	},
	"Risk": {},
	"Links": {
		"Self": "/account-requests/88379"
	},
	"Meta": {
		"TotalPages": 1
	}
}


Step 3 - Authorize Consent

1. Third Party receives a AccountRequestId from the API Provider. The Third Party then creates an Authorization request (using a signed JWT Request containing the AccountRequestId as a claim) for the Customer to consent to the Account request directly with their API Provider. The request is an OIDC Hybrid flow (requesting for code and id_token)

Request : OIDC Hybrid Flow

Response : OIDC Hybrid Flow

Sourced from the NZ Banking Data Security Profile Request Object section

Base 64 Encoded Example
GET /authorize?
response_type=code id_token
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&scope=openid accounts
&nonce=n-0S6_WzA2Mj
&redirect_uri=https://api.mytpp.com/cb
&request=CJleHAiOjE0OTUxOTk1ODd.....JjVqsDuushgpwp0E.5leGFtcGxlI
iwianRpIjoiM....JleHAiOjE0.olnx_YKAm2J1rbpOP8wGhi1BDNHJjVqsDuushgpwp0E
Non-Base64 encoded example of the request parameter object
{
	"alg": "PS256",
	"kid": "GxlIiwianVqsDuushgjE0OTUxOTk"
}
.
{
	"iss": "https://api.alphabank.com",
	"aud": "s6BhdRkqt3",
	"response_type": "code id_token",
	"client_id": "s6BhdRkqt3",
	"redirect_uri": "https://api.mytpp.com/cb",
	"scope": "openid payments accounts",
	"state": "af0ifjsldkj",
	"nonce": "n-0S6_WzA2Mj",
	"max_age": 86400,
	"claims": {
		"userinfo": {
			"openbanking_intent_id": {
				"value": "urn:alphabank:intent:88379",
				"essential": true
			}
		},
		"id_token": {
			"openbanking_intent_id": {
				"value": "urn:alphabank:intent:88379",
				"essential": true
			},
			"acr": {
				"essential": true,
				"values": ["urn:openbanking:nz:sca",
					"urn:openbanking:nz:ca"
				]
			}
		}
	}
}
.
<<signature>>

After the Customer has consented directly with the API Provider via their web application (and confirmed Account access) the API Provider validates the Authorization request and generates an Auth Code and ID Token

HTTP/1.1 302 Found
  Location: https://api.mytpp.com/cb#
    code=SplxlOBeZQQYbYS6WxSbIA
    &id_token=eyJ0 ... NiJ9.eyJ1c ... I6IjIifX0.DeWt4Qu ... ZXso
    &state=af0ifjsldkj


2. The Customer is then redirected to the Third Party. The Third Party will now possess the Authorization Code and ID Token from the API Provider. Note at this point, there is no Access Token. The Third Party will now introspect the ID Token and use it as a detached signature to check:

  • The hash of the Authorization Code to prove it hasn't been tampered with during redirect (comparing the hash value against the c_hash attribute in ID Token)
  • The hash of the State to prove it hasn't been tampered with during redirect (comparing the state hash value against the s_hash attribute in the ID Token)

Example: ID Token

Sourced from the NZ Banking Data Security Profile Request Object section

{
	"alg": "PS256",
	"kid": "GxlIiwianVqsDuushgjE0OTUxOTk"
}
.
{
	"iss": "https://api.alphabank.com",
	"iat": 1234569795,
	"sub": "urn:alphabank:accountRequestId:88379",
	"acr": "urn:openbanking:nz:ca",
	"openbanking_intent_id": "urn:alphabank:intent:88379",
	"aud": "s6BhdRkqt3",
	"nonce": "n-0S6_WzA2Mj",
	"exp": 1311281970,
	"s_hash": "76sa5dd",
	"c_hash": "asd097d"
}
.
<<signature>>

3. Once the state and code validations have been confirmed as successful by use of the ID token, the Third Party will proceed to obtain an Access Token from the API Provider using the Authorization Code they now possess. The Third Party will present its Authorization Code together with the private_key_jwt. The Access Token is required by the Third Party in order to access Customer Account information. The accounts scope should already be associated with the Authorization Code generated in the previous step.

Request : Access Token request using Authorization Code and private_key_jwt

Response : Access Token (with Optional Refresh Token)

POST  /as/token.oauth2 HTTP/1.1
Host: https://authn.alphabank.com
Content-Type: application/x-www-form-urlencoded
Accept: application/json
grant_type=authorization_code
&redirect_uri=https://api.mytpp.com/cb
&code=SplxlOBeZQQYbYS6WxSbIA
&client-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRw
czovL2p3dC1pZHAuZXhhbXBsZS5jb20iLCJzdWIiOiJtYWlsdG86bWlrZUBleGFtcGxlLmN
vbSIsIm5iZiI6MTQ5OTE4MzYwMSwiZXhwIjoxNDk5MTg3MjAxLCJpYXQiOjE0OTkxODM2MD
EsImp0aSI6ImlkMTIzNDU2IiwidHlwIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9yZWdpc3Rlc
iJ9.SAxPMaJK_wYl_W2idTQASjiEZ4UoI7-P2SbmnHKr6LvP8ZJZX6JlnpK_xClJswAni1T
p1UnHJslc08JrexctaeEIBrqwHG18iBcWKjhHK2Tv5m4nbTsSi1MFQOlMUTRFq3_LQiHqV2
M8Hf1v9q9YaQqxDa4MK0asDUtE_zYMHz8kKDb-jj-Vh4mVDeM4_FPiffd2C5ckjkrZBNOK0
01Xktm7xTqX6fk56KTrejeA4x6D_1ygJcGfjZCv6Knki7Jl-6MfwUKb9ZoZ9LiwHf5lLXPuy
_QrOyM0pONWKj9K4Mj7I4GPGvzyVqpaZUgjcOaZY_rlu_p9tnSlE781dDLuw
Non-Base64 JWT client_assertion
{
	"alg": "PS256",
	"kid": "12345",
	"typ": "JWT"
}
.
{
	"iss": "s6BhdRkqt3",
	"sub": "s6BhdRkqt3",
	"exp": 1499187201,
	"iat": 1499183601,
	"jti": "id123456",
	"aud": "https://authn.alphabank.com/as/token.oauth2"
}
.
<<signature>>
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
 
{
	"access_token": "SlAV32hkKG",
	"token_type": "Bearer",
	"expires_in": 3600,
	"refresh_token": "1Sm4HAl33z4"
}


Step 4 - Request Account Data

1. The Third Party can use the Access Token to retrieve Accounts (bulk or specific). 

Where the initial Access Token expires, the Third Party can use the Refresh token in order to obtain a fresh Access Token.

Request : Accounts APIResponse: Accounts API

Example request against the bulk Accounts resource

GET /accounts HTTP/1.1
Authorization: Bearer SlAV32hkKG
x-fapi-customer-last-logged-time: 2017-06-13T11:36:09
x-fapi-customer-ip-address: 104.25.212.99
x-fapi-interaction-id: 93bac548-d2de-4546-b106-880a5018460d
Accept: application/json
HTTP/1.1 200 OK
x-fapi-interaction-id: 93bac548-d2de-4546-b106-880a5018460d
Content-Type: application/json
 
{
	"Data": {
		"Account": [{
				"AccountId": "22289",
				"Currency": "NZD",
				"Nickname": "Bills",
				"Account": {
					"SchemeName": "BECSElectronicCredit",
					"Identification": "80200110203345",
					"Name": "Mr Kevin",
					"SecondaryIdentification": "00021"
				}
			},
			{
				"AccountId": "31820",
				"Currency": "NZD",
				"Nickname": "Household",
				"Account": {
					"SchemeName": "BECSElectronicCredit",
					"Identification": "80200110203348",
					"Name": "Mr Kevin"
				}
			}
		]
	},
	"Links": {
		"Self": "/accounts"
	},
	"Meta": {
		"TotalPages": 1
	}
}

Example request for a specific Account Id

GET /accounts/22289 HTTP/1.1
Authorization: Bearer SlAV32hkKG
x-fapi-customer-last-logged-time: 2017-06-13T11:36:09
x-fapi-customer-ip-address: 104.25.212.99
x-fapi-interaction-id: 93bac548-d2de-4546-b106-880a5018460d
Accept: application/json
HTTP/1.1 200 OK
x-fapi-interaction-id: 93bac548-d2de-4546-b106-880a5018460d
Content-Type: application/json
 
{
	"Data": {
		"Account": [{
			"AccountId": "22289",
			"Currency": "NZD",
			"Nickname": "Bills",
			"Account": {
				"SchemeName": "BECSElectronicCredit",
				"Identification": "80200110203345",
				"Name": "Mr Kevin",
				"SecondaryIdentification": "00021"
			}
		}]
	},
	"Links": {
		"Self": "/accounts/22289"
	},
	"Meta": {
		"TotalPages": 1
	}
}
Request: Refresh Token request using private_key_jwtResponse: Refresh Token
POST  /as/token.oauth2 HTTP/1.1
Host: https://authn.alphabank.com
Content-Type: application/x-www-form-urlencoded
Accept: application/json
grant_type=refresh_token
&refresh_token=1Sm4HAl33z4
&scope=openid accounts
&client-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRw
czovL2p3dC1pZHAuZXhhbXBsZS5jb20iLCJzdWIiOiJtYWlsdG86bWlrZUBleGFtcGxlLmN
vbSIsIm5iZiI6MTQ5OTE4MzYwMSwiZXhwIjoxNDk5MTg3MjAxLCJpYXQiOjE0OTkxODM2MD
EsImp0aSI6ImlkMTIzNDU2IiwidHlwIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9yZWdpc3Rlc
iJ9.SAxPMaJK_wYl_W2idTQASjiEZ4UoI7-P2SbmnHKr6LvP8ZJZX6JlnpK_xClJswAni1T
p1UnHJslc08JrexctaeEIBrqwHG18iBcWKjhHK2Tv5m4nbTsSi1MFQOlMUTRFq3_LQiHqV2
M8Hf1v9q9YaQqxDa4MK0asDUtE_zYMHz8kKDb-jj-Vh4mVDeM4_FPiffd2C5ckjkrZBNOK0
01Xktm7xTqX6fk56KTrejeA4x6D_1ygJcGfjZCv6Knki7Jl-6MfwUKb9ZoZ9LiwHf5lLXPuy
_QrOyM0pONWKj9K4Mj7I4GPGvzyVqpaZUgjcOaZY_rlu_p9tnSlE781dDLuw

A new Access Token and Refresh Token will be returned to the Third Party for them to query /accounts resources

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
 
{
	"access_token": "TYstftas123j",
	"token_type": "Bearer",
	"expires_in": 3600,
	"refresh_token": "XUUGas123ed"
}

Edge Cases

This section provides further information on potential edge cases that may arise via the implementation of Accounts and Payments API Specifications. 

Customer Consent Authorization Interrupt with API Provider

APIScenarioWorkflow StepImpactSolution Options
Payments

Due to an interruption, the Customer does not complete the Authorization of the Payment with the API Provider when redirected by the Third Party (after creating a PaymentId)


Step 3: Authorize Consent

Payment Status remains as Pending or AcceptedTechnicalValidation

The Third Party may choose to implement a separate follow up process which reminds the Customer to complete their Authorization consent steps with the API Provider. This would imply re-using the PaymentId that has a status of Pending or AcceptedTechnicalValidation and re-issuing another Hybrid Flow request to the API Provider. The implementation of how the follow up process is initiated is in the competitive space for the Third Parties to decide.

AccountsDue to an interruption, the Customer does not complete the Authorization of the Accounts request with the API Provider when redirected by the Third Party (after creating an AccountRequestId)Step 3: Authorize ConsentAccount Status remains as AwaitingAuthorisationThe Third Party may choose to implement a separate follow up process which reminds the Customer to complete their Authorization consent steps with the API Provider. This would imply re-using the AccountRequestId that has a status of AwaitingAuthorisation and re-issuing another Hybrid Flow request to the API Provider. The implementation of how the follow up process is initiated is in the competitive space for the Third Parties to decide.