Go to ContentGo to Sidebar navigation
PSD2 Auth

PSD2 Authentication

According to the Second Payment Services Directive (PSD2), to get access to the AIS service it is required to be a legal person with a permit as an Account Information Service Provider, granted by national competent authorities (Finansinspektionen in Sweden). In a similar manner, to get access to the PIS service it is required to have a permit as an Payment Initiation Service Provider.

An eIDAS-issued certificate and end user authorization is required to perform PSD2 authentication/authorization to ultimately gain access to the AIS and PIS APIs.

The permissions granted to the TPP translate to PSD2 roles (entitlements), and are stated in the TPP's eIDAS certificate, those being PSP_AI and PSP_PI, according to the mapping in table below:

PSD2 EntitlementCertificate RolePSD2 Scope
Account Information ServicePSP_AIAIS
Payment Initiation ServicePSP_PIPIS

Only roles present in the certificate may be used, and requests that do not follow this will be denied. The TPP may perform authentication with a reduced scope if desired (such as only AIS scope even if capable of requesting AIS and PIS). More information on this will be presented below.

PSD2 Fallback

On the 17th of February of 2020, Finansinspektionen (FI) approved SBAB Bank AB's application to be exempted from the obligation to provide a contingency mechanism in accordance with Article 33(4) of the RTS/PSD2 (FI Dnr 19-13438). For this reason, SBAB no longer provides a contingency mechanism for the AIS/PIS interfaces.

Certificate-based authentication

PSD2 API calls (AIS and PIS) require a valid eIDAS certificate belonging to the TPP.

However, since in the Sandbox no TLS certificate validation is possible, you must use a test certificate as a header named X-PSD2-CLIENT-TEST-CERT, sending it as a Base64-encoded string. In contrast with a production environment, AIS and PIS scopes will not be validated against the certificate, no TLS handshake will be performed, and no actual BankID request will be performed, meaning that you'll get immediate authentication success.

If you want to create a self-signed certificate for testing purposes, you can follow the instructions given in this blog post.

User authorization

The end user of the service, also known as Payment Service User (PSU) in PSD2 nomenclature, grants access to its data by using Swedish BankID. Authentication and authorization requests will initiate a request to the PSU's BankID and return a pending authorization code and a BankID autostart token. The pending authorization code is used to continue the authentication/authorization flow, and the autostart token should be used by the TPP to trigger the PSU's BankID. More information on BankID and the autostart token can be found on BankID's developer information page.

Available flows

SBAB provides two flows that TPPs can use to obtain the PSU's consent to access its data: authenticate and authorize flows. The purpose is to separate the customer's consent for different use cases.

Both flows will provide the TPP with a BankID autostart token, which should be user to trigger the PSU's BankID as described above. A pending authorization code will also be provided, which can be used to obtain the appropriate tokens for the initiated flow after a successful BankID grant is given by the PSU (note that this code is used both for authentication and authorization flows, the word "authorization" in its name should not be taken literally).

In addition to the two mentioned flows, a non-standard flow used for a non-authenticated user is also available for transfers and AIS operations. This flow is issuing a restricted access token by calling the token endpoint directly in a single request without BankID authentication.

Authenticate flow

This flow is used to obtain an access token that can be used to perform several operations on the PSU's account, such as reading account information and listing transactions.

The result of this flow is an access token that can only be used during a 30 minute time frame. This flow has no limitations to how many times it is executed but requires end user interaction (BankID interaction) each time the token validity expires. This flow can never produce a refresh token.

Authorize flow

This flow is used to obtain a short-lived access token with the same capabilities as the one from authenticate flow above, and additionally a refresh token, which can be used to obtain more short-lived access tokens for a period of up to 180 days without further end user interaction.

More specifically, access tokens obtained from this flow, both the first and any subsequent obtained through the refresh token, are valid for only 5 minutes.

The refresh token, in contrast, will be valid for 180 days and may be used up to 4 times a day to obtain new access tokens.

The existing authorize endpoint /psd2/auth/1.0/authorize using bankID signing, will be deprecated 2023-08-21 and replaced by the new endpoint /psd2/auth/2.0/authorize using bankID authentication. The same request parameters as before can be used when calling the new endpoint, only the URL is changed.

Non Authenticated flow

This new non-standard Oauth flow is used to reduce the number of Strong Customer Authentications (SCA) when executing transfers for a PSD2 client. An access token obtained from this flow has a default TTL of 30 minutes. The flow is reducing the number of SCAs to only 1 instead of 2 by the following steps:

  1. Get a restricted access token without BankID authentication by calling the token endpoint (no SCA is needed any longer).
  2. Validate/initiate the transfer with the issued token from step 1 as in current flow.
  3. Execute the actual transfer with a BankID signing exactly as as in current flow (now the single SCA for this flow).

Please note that the old flow with BankID authentication before signing the transaction, requiring a total of 2 SCAs, is still available.

In addition, also end users authenticated in a TPP app can execute AIS operations on accounts without any further SCA with the same Non Authenticated flow as described for transfers.

If the restricted access token is provided by the TPP app together with a mandatory PSU-IP-Address header containing the PSU ip address, no SCA is needed to retrieve account information.

Please note that the old flow with BankID authentication fetching AIS information, requiring one SCA, is still available.

Please note that when retrieving account information in the sandbox, there is no difference between the flow with BankID authentication and the non-authenticated flow since it is only possible to use one type of static sandbox token for each user. These two flows are thus the same in the sandbox but will be different in production.

Retrieving Access Tokens

Irrespective of which flow is being executed, after the PSU allows the TPP to access its data using BankID, an access token must be obtained. Such token will be provided to all calls executed against protected SBAB APIs.

In order to do so, the TPP must use the pending authorization code provided when initializing the authentication/authorization flow. This is the last step of the process, and it may also fail for a number of reasons, beyond the obvious reasons of malformed requests:

  • expired eIDAS certificate
  • the user haven't yet completed the BankID operation
  • expired pending authentication code
  • expired refresh token
  • refresh token used more than 4 times in a day
  • KYC (Know Your Customer) questions not answered by the user

Most of these failures can be amended by repeating the authentication/authorization process. If it fails because of KYC questions, then you must direct the user to access its SBAB account through the SBAB phone app or the web, as there is no API to answer these questions, and no access will be granted until they are answered.

With that, the possible flows, requests and response combinations are summarized below:

FlowScopeRequested Token TypeResponseAccess Token Validity
AuthenticateAIS/PISAccess TokenAccess Token30 minutes
AuthorizeAIS/PISAccess TokenAccess Token + Refresh Token5 minutes
AuthorizeAISRefresh TokenAccess Token5 minutes
Non AuthenticatedAIS/PISAccess TokenAccess Token30 minutes

API usage

As mentioned, the flows for PSD2 are authentication, authorization and non authenticated. For any calls to execute these flows, there are two mandatory headers:

  • PSU-IP-Address: it should contain the IP address of the PSU in IPv4 format or IPv6 format
  • X-PSD2-CLIENT-TEST-CERT: this field should contain a Base64-encoded test PSD2 certificate; as explained above, the contents of this certificate will not be validated in any way, but it needs to be a well-formed certificate

Authenticate flow

You start this flow by making a call to the PSD2 authenticate endpoint:

curl -X GET -G \ "https://developer.sbab.se/sandbox/psd2/auth/1.0/authenticate" \ -H "Accept: application/json" \ -H "X-PSD2-CLIENT-TEST-CERT: -----BEGIN CERTIFICATE-----MIIEEjCdCAv...-----END CERTIFICATE-----" \ -H "PSU-IP-Address:" \ -d user_id=191212121212 \ -d scope=AIS,PIS

Again, observe the mandatory headers and some important parameters:

  • user_id: contains the PSU's Swdish personal number
  • scope: specifies the desired scopes; as exposed before, the acceptable values are tied to the entitlements present in the certificate (not validated in sandbox, though), and if not specified then it defaults to all the entitlements present in the certificate

The response to this request should look like the following:

{ "pending_authorization_code": "2fe95e3b-380b-4ad2-bb77-44caa51605b8", "autostart_token": "d35ae4dc-f873-419d-8c43-d85dbe92ab62" }

As explained in the Enterprise Authentication section above, the autostart_token would need to be used to initiate BankID, which is not needed in the sandbox.

The next step is requesting an access token for the user:

curl -X POST \ "https://developer.sbab.se/sandbox/psd2/auth/1.0/token" \ -H "Accept: application/json" \ -H "X-PSD2-CLIENT-TEST-CERT: -----BEGIN CERTIFICATE-----MIIEEjCdCAv...-----END CERTIFICATE-----" \ -H "PSU-IP-Address:" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d grant_type=pending_authorization_code \ -d pending_code=2fe95e3b-380b-4ad2-bb77-44caa51605b8

Observe some parameters:

  • grant_type: in this flow it is required to be pending_authorization_code
  • pending_code: contains the pending_authorization_code obtained in the previous request

Other than a failure caused by many of the various situations exposed above, the response should look like the following:

{ "access_token": "586515f1-e9a7-4eb0-96bd-2295437da10e", "expires_in": 300, "auth_method": "authenticate", "token_type": "bearer" }

Now you can use the given access_token as a bearer token in any requests to the Enterprise API for the next 5 minutes (300 seconds).

Authorize flow

For this flow, you start by making the following request (please note that the old flow using /psd2/auth/1.0/authorize will be deprecated but is still available):

curl -X GET -G \ "https://developer.sbab.se/sandbox/psd2/auth/2.0/authorize" \ -H "Accept: application/json" \ -H "X-PSD2-CLIENT-TEST-CERT: -----BEGIN CERTIFICATE-----MIIEEjCdCAv...-----END CERTIFICATE-----" \ -H "PSU-IP-Address:" \ -d scope=AIS,PIS \ -d user_id=191212121212

Other than the requested endpoint, the parameters, headers and everything else work exactly as for the authorization flow above. However the response of the access token request changes. Given a similar token request:

curl -X POST \ "https://developer.sbab.se/sandbox/psd2/auth/1.0/token" \ -H "Accept: application/json" \ -H "X-PSD2-CLIENT-TEST-CERT: -----BEGIN CERTIFICATE-----MIIEEjCdCAv...-----END CERTIFICATE-----" \ -H "PSU-IP-Address:" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d grant_type=pending_authorization_code \ -d pending_code=2fe95e3b-380b-4ad2-bb77-44caa51605b8

The result is instead something like the following:

{ "access_token": "583a9e70-afbc-4f0e-8ab7-9ff0ad1eb906", "expires_in": 300, "refresh_token": "47b5af0f-5275-404b-a9bf-ea4f95f66a39", "auth_method": "authorize", "token_type": "bearer" }

Again, you are given an access_token valid for 5 minutes (300 seconds), but you also receive a refresh_token. This token is valid for 180 days and can be used to retrieve new access tokens up to 4 times a day.

In order to obtain an access token from a refresh token, you instead make a different request to the token endpoint, like below:

curl -X POST \ "https://developer.sbab.se/sandbox/psd2/auth/1.0/token" \ -H "Accept: application/json" \ -H "X-PSD2-CLIENT-TEST-CERT: -----BEGIN CERTIFICATE-----MIIEEjCdCAv...-----END CERTIFICATE-----" \ -H "PSU-IP-Address:" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d grant_type=refresh_token \ -d refresh_token=47b5af0f-5275-404b-a9bf-ea4f95f66a39

This request is identical to the one above except for two key differences in its parameters:

  • grant_type: must contain the value refresh_token
  • pending_code: this parameter is now absent
  • refresh_token: this parameter is mandatory for this kind of request, and its value is the value of the refresh_token field received in the previous token endpoint response

The response is similar to the one obtained previously from this endpoint:

{ "access_token": "eb66eae0-31b2-4c80-b05c-d917c3e7f3bf", "expires_in": 300, "refresh_token": "47b5af0f-5275-404b-a9bf-ea4f95f66a39", "auth_method": "authorize", "token_type": "bearer" }

Note the new access_token, again valid for 5 minutes (300 seconds). As already mentioned, this operation with the refresh token may be executed up to 4 times a day (such restriction do not exist in the sandbox), and the refresh token is still the same, still valid for 180 days from the moment it was created (in other words, its validity is not extended when requesting new access tokens with an existing refresh token).

After the 180 days are passed, the refresh token expires, and a new user authentication will be required, demanding new user interaction to get a new refresh token.

Non Authenticated flow

For this flow, you start by making this request to get a token without BankID authentication:

curl -X POST \ "https://developer.sbab.se/sandbox/psd2/auth/1.0/token" \ -H "Accept: application/json" \ -H "X-PSD2-CLIENT-TEST-CERT: -----BEGIN CERTIFICATE-----MIIEEjCdCAv...-----END CERTIFICATE-----" \ -H "PSU-IP-Address:" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d grant_type=non_authenticated_token \ -d user_id=196306151751

The parameters to use are:

  • grant_type: must contain the value non_authenticated_token
  • user_id: the Swedish personal number of the account owner

The response contains the access token and expiration in seconds:

{ "access_token": "16086f8c-828d-4e01-a30a-0770353decd1", "expires_in": 1800, "token_type": "bearer" }

The following applies for the new non-authenticated flow:

  • This returned access token can be used to initiate a transfer:


    and check the status of the ongoing transfer:


    The non-authenticated flow can also be used to perform AIS operations like

    • v2/accounts-numbers
    • v2/accounts
    • v2/accounts/{}accountNumber}
    • v2/accounts/{}accountNumber}/transfers
    • v2/accounts/{}accountNumber}/transfers/{transfer-id}
    • v2/accounts/{account-number}/{currency}/{amount}
  • The PSD2 certificate must have PIS scope for executing a transfer.

  • The PSD2 certificate must have AIS scope for executing AIS operations.

  • The TTL of the token is configured per TPP. The default TTL is 30 minutes.

  • A special grant type non_authenticated_token is used for the token request.

  • If all the KYC questions have not been answered, the operation will not be executed.

  • If the validation of a transfer fails due to the account balance, faulty transfer date or any other failure, the transfer will not be executed.

  • The personal identification number will be given in the request parameter user_id.

  • All ordered transfers using grant type non_authenticated_token must eventually be signed with BankID.

Try it yourself

We recommend that you test the steps above in our sandbox environment, if you haven't done so yet.

Test the API

Production Gateway URL

When you move into production use of our APIs, remember to change the domain from the sandbox one to the production one: