TPP Setup in PSD2 Sandbox

After registering an application on OP Developer, the TPP must ensure that they are in possession of valid certificates prior to registering using the TPP registry. The TPP needs:

  • Valid eIDAS certs (QWAC), or generated certs from OP for TLS MA
  • Keypair for signing JWTs for use with ES256 (QSEALC)
  • A signed Software Statement Assertion (SSA, signed with the key from step 2)
  • A signed registration JWT with the SSA as one of its fields.

Java helper app

Certificate management and TPP registration are complicated operations. To help you get started, we have provided a Java application which you can use to complete these steps in the sandbox environment, and which you may find helpful when building your production application.

Certificates

The TPP must either possess valid eIDAS certificates or use our TPP certificate generation API for generating certificates for use in our PSD2 sandbox environment.

Two types of certificates are required:

CertificateAlt NameUse
QWACMTLS cert/keyTransport Layer Security: Mutually authenticated TLS
QSEALCSigning cert/keyDigital Signatures, i.e. signing JWTs.

If the TPP does have valid certificates, they may choose to ignore this step and move on to TPP registration (below).

Certificates can be purchased from Qualified Trust Dervice Providers (QTSPs). The European Union maintains a list of Trust Services. Search the list by Type of Service and select "Qualified certificate for electronic seal" and "Qualified certificate for website authentication", and select countries you are interested in.

More information on certificates at e.g. Open Banking Europe's faq.

Generating certificates for sandbox

The certificate generation service provides two certificates: one for emulating QWAC (for establishing mTLS), and another for emulating QSEALC (JWT signing).

Once the certificates have been generated and delivered to the TPP, the generation service makes the public keys available to services in our sandbox environment. In other words, the TPP does not need to publish a JWKS endpoint for their app, unless they want to use keypairs they have obtained from another authority.

Call the certificate generation API as follows:

curl -X POST -v 'https://sandbox.apis.op-palvelut.fi/oop-test-client-certs-psd2/v1/client-cert?c=<COUNTRY>&cn=<TPP_NAME>' \
-H 'x-api-key: <APP_API_KEY>' \
-H 'Content-Length: 0' \
-H 'Accept: application/json' \

Query parameters

Parameter nameExplanation
cCountry as ISO 3166-1 Alpha 2 (e.g. FI).
cnCommon name of the TPP company (e.g. "Brinklyfy.io").

Sample Response

HTTP/1.1 201 Created
Date: Tue, 05 Mar 2019 14:03:25 GMT
Content-Type: application/jwk-set+json; charset=UTF-8
Location: /oop-test-client-certs-psd2/v1/client-cert/[tppId]

{
  "publicJwks": {
    "keys": [
      {
        "kty": "RSA",
        "e": "AQAB",
        "use": "sig",
        "kid": "b9_EDg",
        "x5c": [
          "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"
        ],
        "alg": "RS256",
        "n": "lW7KSQnUjSJFaUDi3JWe3C7R0Cbl8PQdgdZYj7TLjUei9ImgqOGhm3d41xol-BZxTHQltzZ3KvhqWvXEEzMUn3fs7MKngf0s8GgH5VwJrx3rRaXYEkm-R--rXN2JHbLiKO7w2CFqgc9XeOOKtOV0xsGLUiUnFqoIMxv-JiZ8UM5OU4Lk9wqdfsXDNXCRJHBk3d4DTBwoQM8ZbvpJ_dJKO5T8V8T6823I2BJ39b9SGCDLeTfWkBl5Y3RuBCRQZbI8Q-LgCOHQRBlF2gNWEXITMgAoA0ZGVpjejOFb_CeogPkt1MyzdR90H00kTMm76BSpWiTqm20fC5r7th_HRrXAzxU6T5S9UssmpB9-7N8j_kc4Ht_2CzG_mmzDTLzkYZZpgtr5Dxb-MVc36xurJKP0-7riQIckFnoc6ZAp9gtVlmlmBdBfv0WeI8BuXMam2as9DD6XRLhkQFyiht6qbB6Vw03X80rU0SnvM1r9g5TyBi4eE_FWNIwTEZwGrbYJmiyf7hNsqMLYvey8xiA0POFzBctgoK5ZnNaV6ZWy-a6ERU1liOqhQ5WvB6YGBHs5wLa6ThADszXltXGVIxyJ7-4mxlFKa_CTcxE2kt7W9BNBUiezHF-rK6jJCPcMpb6BDkkmEwpR__HhmsGIoyvREOlwSq8a8pmMSz-BdU7MpFLt99c"
      },
      {
        "kty": "EC",
        "use": "sig",
        "crv": "P-256",
        "kid": "R2Zktg",
        "x5c": [
          "MIICnDCCAkKgAwIBAgIER2ZktjAKBggqhkjOPQQDAjBBMQswCQYDVQQGEwJGSTEyMDAGA1UEAwwpT1AgU2VydmljZXMgUFNEMiBBVFkgVGVzdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMTkwMzE0MDcyODI4WhcNMjQwMzE0MDcyODI4WjBZMQswCQYDVQQGEwJGSTEjMCEGA1UEAwwaU0FOREJPWFN1Y2Nlc3NmdWwgRmluYW5jZXMxJTAjBgNVBGEMHFBTRE9QLVRFU1QtVFBQLWI1M2QxYWY2LThjNTYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQQYYh2/5q/HbI2GtKe/cHAyn6Ba+GcpC/uAZSUHiEhUQoDBfIJLtbNQToiHx1UjasiQwjXahR2/BGFc9HQSo7Jo4IBDjCCAQowCQYDVR0TBAIwADAUBgNVHSAEDTALMAkGBwQAi+xAAQEwgZAGCCsGAQUFBwEDBIGDMIGAMH4GBgQAgZgnAjB0MEwwEQYHBACBmCcBAQwGUFNQX0FTMBEGBwQAgZgnAQIMBlBTUF9QSTARBgcEAIGYJwEDDAZQU1BfQUkwEQYHBACBmCcBBAwGUFNQX0lDDBxOYXRpb25hbCBDb21wZXRlbnQgQXV0aG9yaXR5DAZFVS1OQ0EwDgYDVR0PAQH/BAQDAgeAMCUGA1UdIwQeMByAFJ7XE/T+dSSKrrLeC7l/vhAMF7DOggQPulJhMB0GA1UdDgQWBBTLUlO/XYxNo0RKqaCLP7/aWD9rwTAKBggqhkjOPQQDAgNIADBFAiB3Klrjlx2Igdtx7sE8N8XpGg5Y7bnXGvb9eBCEZASZoAIhAI9qJSiRvOPjKjqLGMQ9uoTFODLMQBh/dxj96UnYHHan"
        ],
        "x": "EGGIdv-avx2yNhrSnv3BwMp-gWvhnKQv7gGUlB4hIVE",
        "y": "CgMF8gku1s1BOiIfHVSNqyJDCNdqFHb8EYVz0dBKjsk",
        "alg": "ES256"
      }
    ]
  },
  "privateJwks": {
    "keys": [
      {
        "kty": "RSA",
        "d": "OOoOj4z38J0p9LGq9jriW5hVf0MhdwlzJ51885b3pCKxtROqJkhxpeX2F281IO1jT6w5JTPQZYRh9az_dhSReT9S9MYayI6mDBaDU18frRvnHQrSZfzCRWHKUb9q1u3n55FCF_96MmDHPxrjHIz8UisrJilSXvZ50wWJYfxsgtZgzLvg-xqG697kv7jU_xzzvfEuLlHXHwAB_tvDTLJIZbMT_VXgAtFAmtNF70pkOR5cgRm8Vfvt2Oxibp9qI6GkBHMnwxpGmXlKuoNkx5Y8K2IV21FrvtXQhbXbtAliy2SciR1CCIznTHi0J676K6Wa7uN6m6IPHft0fWRTIOJewaludIKzYNgJ2__pNczjor4sMv3L-El-JpEbnLksoo_QerQOkQbzgsjmknVfOTxCXSdT8u6f2YpkIrpeHNFtqnpMDrHsywcrryhOlyerbnTFt5EYawpLnDz7_fVHcfPBfW-m4XE8aeN2aUCfOraMpAr3oPRJ8eJcQGVBwBR4vpMYv5u_eK-sg9BakFxI34fuujm7z0AfkKeYc2wqAzagkV_ECiinH_5ow4-m1e9qVoefKawtSTTXoMwrV39GhCBJGYbpXEMac64-j7rJu3eUMsUcVLnQYqNkcUn3pxaQSvQZydeNSDoczpZajwvacNaJkNVO_vlyYs03x7cr9NCnM-k",
        "e": "AQAB",
        "use": "sig",
        "kid": "b9_EDg",
        "x5c": [
          "MIIGKDCCBBCgAwIBAgIEb9/EDjANBgkqhkiG9w0BAQUFADBBMQswCQYDVQQGEwJGSTEyMDAGA1UEAwwpT1AgU2VydmljZXMgUFNEMiBBVFkgVGVzdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMTkwMzE0MDcyODI4WhcNMjQwMzE0MDcyODI4WjBZMQswCQYDVQQGEwJGSTEjMCEGA1UEAwwaU0FOREJPWFN1Y2Nlc3NmdWwgRmluYW5jZXMxJTAjBgNVBGEMHFBTRE9QLVRFU1QtVFBQLWI1M2QxYWY2LThjNTYwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCVbspJCdSNIkVpQOLclZ7cLtHQJuXw9B2B1liPtMuNR6L0iaCo4aGbd3jXGiX4FnFMdCW3Nncq+Gpa9cQTMxSfd+zswqeB/SzwaAflXAmvHetFpdgSSb5H76tc3YkdsuIo7vDYIWqBz1d444q05XTGwYtSJScWqggzG/4mJnxQzk5TguT3Cp1+xcM1cJEkcGTd3gNMHChAzxlu+kn90ko7lPxXxPrzbcjYEnf1v1IYIMt5N9aQGXljdG4EJFBlsjxD4uAI4dBEGUXaA1YRchMyACgDRkZWmN6M4Vv8J6iA+S3UzLN1H3QfTSRMybvoFKlaJOqbbR8Lmvu2H8dGtcDPFTpPlL1SyyakH37s3yP+Rzge3/YLMb+abMNMvORhlmmC2vkPFv4xVzfrG6sko/T7uuJAhyQWehzpkCn2C1WWaWYF0F+/RZ4jwG5cxqbZqz0MPpdEuGRAXKKG3qpsHpXDTdfzStTRKe8zWv2DlPIGLh4T8VY0jBMRnAattgmaLJ/uE2yowti97LzGIDQ84XMFy2Cgrlmc1pXplbL5roRFTWWI6qFDla8HpgYEeznAtrpOEAOzNeW1cZUjHInv7ibGUUpr8JNzETaS3tb0E0FSJ7McX6srqMkI9wylvoEOSSYTClH/8eGawYijK9EQ6XBKrxrymYxLP4F1TsykUu331wIDAQABo4IBDjCCAQowCQYDVR0TBAIwADAUBgNVHSAEDTALMAkGBwQAi+xAAQEwgZAGCCsGAQUFBwEDBIGDMIGAMH4GBgQAgZgnAjB0MEwwEQYHBACBmCcBAQwGUFNQX0FTMBEGBwQAgZgnAQIMBlBTUF9QSTARBgcEAIGYJwEDDAZQU1BfQUkwEQYHBACBmCcBBAwGUFNQX0lDDBxOYXRpb25hbCBDb21wZXRlbnQgQXV0aG9yaXR5DAZFVS1OQ0EwDgYDVR0PAQH/BAQDAgeAMCUGA1UdIwQeMByAFJ7XE/T+dSSKrrLeC7l/vhAMF7DOggQPulJhMB0GA1UdDgQWBBS8U3TH8SIf2qszhtek6zH7s+0zgzANBgkqhkiG9w0BAQUFAAOCAgEArf65PT9AqlNDwqsVNr9gIDl0cXpCdK7xlCx8T1J5GLl1HxruRLfqPlI8zIBR2rhZr60i8+YMDARWc2rN2PPTNlmrH2cVwWiZGDC0s50PqJjNYk4woGN2WXE70llzfdfojzy8fl89yfgUmNOi1QiSvhw/5nMM81I05Yisymfobo+7gWz4HaqEm6eXM8wiF0UuXuCQ+LY/g6duHPHNoGXX3NS/tSo2JR/8JL5MoKI9fBiD63K48fmrQnLvE1vxWbH9LB7ZaLqi2yVoIi92IBNDy19KCjRM2JcMk/vMF4N+CePYDwY8HHDHfAvf1WMRJgCRuq//Ucu1AV+HyTfMRTeps3vPbnFWzLbOarNVDBUldmPD1dIOUhfmsXqWpgR1hn5Lu7Si136EFcCHa8RxyeNBY7i6Vhumb5EEeNAWMpkvRLhdMAFfnRB/hEMK0r2oIl07mNjzWdKVeI8nEsnX6EQ2cYfTiP2W1BTS9o9ipPAOSx+QrjVZmVTk1r6OcYIEJVBDrAEvF9yr0OM5xwpYOcoCxQfjiHLUAuuw8bEETXt8PDRbsJG7KFS8VNh4qp2671jazo0GCW6edW7GNsYpixT6jDqxsZVbeMKxBXm6W+rnYJPad67R/FnJLoI2VhVp6c/2xlkQWzVJurNMpG6Mwyjb+ICSajtb34cY+pLTe20MPI0=",
          "MIIFbjCCA1agAwIBAgIED7pSYTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEqMCgGA1UEAwwhT1AgU2VydmljZXMgUFNEMiBBVFkgVGVzdCBSb290IENBMB4XDTE5MDIwMTEwMzMwOFoXDTI5MDIwMTEwMzMwOFowQTELMAkGA1UEBhMCRkkxMjAwBgNVBAMMKU9QIFNlcnZpY2VzIFBTRDIgQVRZIFRlc3QgSW50ZXJtZWRpYXRlIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAy8xwu7YolrqHe+Nc+S8BQBSKCj4VYRJpv7v2zlY3Nk2MdYwPa4R/VNCENNSJx2s/dEgcnq/Y3Tv6nPyWi5Rt8QkB2a+bWKcrDXpgFeVfPpWFnLUqG7mRrWOWqqVXq5pl6Qs0VWQR8W1GP/3vre8h1XcUosNv5k8cLkKQiAwh+3gOuTAqvl+3l4hF89DZWubbDOMJmaiHjomFxI+5bu9w8PHZHmeT9IgeZLG7/IYllfq6wE8VM1VPLNR2zP2/sOVCpHxo4sbXiskeVzdmvN7FnHfpbslE0/TJYSzjBIzfRH6wwbrMARicfD3hmmw921tUORO00mEU++OrUqaAJd50I7RObdqbISphUCyUdPoujvMNIZezjHkiME0w1W1jg9tU1qh0+yBb/8mz8VOqYnNGwRjt2IuSzC65n/Uq5q+DgFA+i9jeL5W6oIPNLsGzVAPnysDZcxxZcX2PA1XxomvUf4mvyn3H67LiZTsCNiIOO+LJxjD95clYGcfnVGDzVs2z2r4ldQ1sOSqCn5wuOHtkfqzuzO8o23z7nK2dPDYXL5y8pp0otPOSGCp72W6Ds67w92NVSaQ8q/4Nj6C+dhqpOdiCRsiwPb+GzbB8eZvuGoFqugJz665xm2P+mK12dScOnCj7Cr+BT0lpnOPdas64XEDQj7n0tzIxksdpARXHt1sCAwEAAaN2MHQwDAYDVR0TBAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwNQYDVR0jBC4wLIAU9XrGSy6qu3tdo3zQxZGmzD6fRLqCFC2sa019f+DVMMlPMn4K/pnsmKIbMB0GA1UdDgQWBBSe1xP0/nUkiq6y3gu5f74QDBewzjANBgkqhkiG9w0BAQUFAAOCAgEAW5JY0ep4uAFYRdoSEpxIdH9yu4FDsRxceWzufFYsyTTM5AFw0uKFJpetAkhh8oCUys7Bm9LdtcM7tvPPOXnFKc6vRfR69cZqNJXoxQh7iq0HkE18oMiW3f18+pbyUnXC9FLQtqdXPKOYeIgZAKMOEvcURkPMOC3wMm3o7sxwJ960jtriYqK5C0guB8OJ7cJQOJ4wj++qyRivoEgm3O0/m5VmfTrM1nBX4pxYyTiNnLWdnyDJ6DG9J0DLNkY3uqD+QhGczAkG4jVisjrOmyn7Md116B0oJPUR9smUNhNR+JHTksXWSdlHz7ofLXfJaKmoQK/rzFIuLj2WxG/TsKv0tGfKqbZPZAKAhL/gqEWp5gzkym1lFXDSX2qi+6Co6OWRXSgQJXd1dxPTxhCXxkVW3YRXNvgq0xnlyNa7ONzu1R/MlwOTJmqOSiic2kG7A/1MhEm76dhb36cnd3fZ6yihPFnLFRDTuaYC9zXhm7Ri5IE96xdHD0d+RlLjVlR8Ugfsh995oKpQKKpmugksFqg88qMcm6DLMmomhEapeaKFMf+JiqunwHp3JL76Pw6rh5VNIeSey8wW31sHbYz31TmYWulAAE40231tAL/D/Gyt/50Nrq8VpyU85Z6+x7kp3PVb1STx8ZhN813AYDgJTPYtIvP4SVIbkmpyQ4SR+G6E7sc="
        ],
        "alg": "RS256",
        "n": "lW7KSQnUjSJFaUDi3JWe3C7R0Cbl8PQdgdZYj7TLjUei9ImgqOGhm3d41xol-BZxTHQltzZ3KvhqWvXEEzMUn3fs7MKngf0s8GgH5VwJrx3rRaXYEkm-R--rXN2JHbLiKO7w2CFqgc9XeOOKtOV0xsGLUiUnFqoIMxv-JiZ8UM5OU4Lk9wqdfsXDNXCRJHBk3d4DTBwoQM8ZbvpJ_dJKO5T8V8T6823I2BJ39b9SGCDLeTfWkBl5Y3RuBCRQZbI8Q-LgCOHQRBlF2gNWEXITMgAoA0ZGVpjejOFb_CeogPkt1MyzdR90H00kTMm76BSpWiTqm20fC5r7th_HRrXAzxU6T5S9UssmpB9-7N8j_kc4Ht_2CzG_mmzDTLzkYZZpgtr5Dxb-MVc36xurJKP0-7riQIckFnoc6ZAp9gtVlmlmBdBfv0WeI8BuXMam2as9DD6XRLhkQFyiht6qbB6Vw03X80rU0SnvM1r9g5TyBi4eE_FWNIwTEZwGrbYJmiyf7hNsqMLYvey8xiA0POFzBctgoK5ZnNaV6ZWy-a6ERU1liOqhQ5WvB6YGBHs5wLa6ThADszXltXGVIxyJ7-4mxlFKa_CTcxE2kt7W9BNBUiezHF-rK6jJCPcMpb6BDkkmEwpR__HhmsGIoyvREOlwSq8a8pmMSz-BdU7MpFLt99c"
      },
      {
        "kty": "EC",
        "d": "dgFe-YT6xMaQ-xv4TQbt64bj6tTf3SkS7devXsOFqIo",
        "use": "sig",
        "crv": "P-256",
        "kid": "R2Zktg",
        "x5c": [
          "MIICnDCCAkKgAwIBAgIER2ZktjAKBggqhkjOPQQDAjBBMQswCQYDVQQGEwJGSTEyMDAGA1UEAwwpT1AgU2VydmljZXMgUFNEMiBBVFkgVGVzdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMTkwMzE0MDcyODI4WhcNMjQwMzE0MDcyODI4WjBZMQswCQYDVQQGEwJGSTEjMCEGA1UEAwwaU0FOREJPWFN1Y2Nlc3NmdWwgRmluYW5jZXMxJTAjBgNVBGEMHFBTRE9QLVRFU1QtVFBQLWI1M2QxYWY2LThjNTYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQQYYh2/5q/HbI2GtKe/cHAyn6Ba+GcpC/uAZSUHiEhUQoDBfIJLtbNQToiHx1UjasiQwjXahR2/BGFc9HQSo7Jo4IBDjCCAQowCQYDVR0TBAIwADAUBgNVHSAEDTALMAkGBwQAi+xAAQEwgZAGCCsGAQUFBwEDBIGDMIGAMH4GBgQAgZgnAjB0MEwwEQYHBACBmCcBAQwGUFNQX0FTMBEGBwQAgZgnAQIMBlBTUF9QSTARBgcEAIGYJwEDDAZQU1BfQUkwEQYHBACBmCcBBAwGUFNQX0lDDBxOYXRpb25hbCBDb21wZXRlbnQgQXV0aG9yaXR5DAZFVS1OQ0EwDgYDVR0PAQH/BAQDAgeAMCUGA1UdIwQeMByAFJ7XE/T+dSSKrrLeC7l/vhAMF7DOggQPulJhMB0GA1UdDgQWBBTLUlO/XYxNo0RKqaCLP7/aWD9rwTAKBggqhkjOPQQDAgNIADBFAiB3Klrjlx2Igdtx7sE8N8XpGg5Y7bnXGvb9eBCEZASZoAIhAI9qJSiRvOPjKjqLGMQ9uoTFODLMQBh/dxj96UnYHHan"
        ],
        "x": "EGGIdv-avx2yNhrSnv3BwMp-gWvhnKQv7gGUlB4hIVE",
        "y": "CgMF8gku1s1BOiIfHVSNqyJDCNdqFHb8EYVz0dBKjsk",
        "alg": "ES256"
      }
    ]
  },
  "publicJwksUrl": "https://example.generated.tpp/OP-TEST-TPP-b53d1af6-8c56"
}

The response contains everything you need for using PSD2 sandbox. See JWKS for more info on JWKs.

Some notes on each item:

FieldExplanationNote
publicJwksPublic JWKs for your applicationkty: RSA contains the QWAC emulation JWK. kty: EC contains the signing key (QSEALC emulation).
privateJwksPrivate JWKs for your appAs above, but for private keys.
publicJwksUrlJWKS available to sandbox servicesThis URL contains the above public keys for our sandbox services. In other words, TPP's are NOT required to set up a published JWKS endpoint for testing. If the TPP does not create their own JWKS endpoint, this value must be passed on in the registration call (field software_jwks_endpoint ).

Note that the Location header contains a URI with tppId as its last element. Extract and save this value, as it is needed in TPP registration. Be aware that TPP ID is NOT equal to client ID.

Using the JWKS

The response value contains all the information needed for emulating PSD2 security measures.

  • typ: RSA - MTSL / QWAC emulation

    • Client certificate (public key) in the first element of the x5c array
    • Your private key, which must be built from n, e, and d in the corresponding privateJwks element.

      • Extract n, d and e
      • Base64urldecode n, d and e
      • Find p: the common factor of n, d and e
      • Resolve q: n divided by p. If p > q, swap p and q
      • Resolve first exponent: d % (p - 1)
      • Resolve second exponent: d % (q - 1)
      • Find the coefficient: q.modInverse(p)
      • Create the key set: new RSAPrivateCrtKeySpec(n, e, d p, q, exp1, exp2, coeff). Generate the private key.
      • Save the certificates in PEM format and create a p12 keystore.

Extracting private key

public void extractsCertificateAndPrivateKey() throws Throwable {
      JSONObject response = new JSONObject(jwkStr);
      JSONObject jwks = response.getJSONObject("privateJwks");
      JSONObject jwk = jwks.getJSONArray("keys").getJSONObject(0);

      BigInteger nBigInt = new BigInteger(1, java.util.Base64.getUrlDecoder().decode(jwk.getString("n")));
      BigInteger dBigInt = new BigInteger(1, java.util.Base64.getUrlDecoder().decode(jwk.getString("d")));
      BigInteger eBigInt = new BigInteger(1, java.util.Base64.getUrlDecoder().decode(jwk.getString("e")));

      tppPrivateCertKey = createCrtKey(nBigInt, eBigInt, dBigInt); 

      String tppPrivateKeyStr = toPemString("RSA PRIVATE KEY", tppPrivateCertKey.getEncoded());
      BufferedWriter privateKeyWriter = new BufferedWriter(new FileWriter("key.pem"));
      privateKeyWriter.write(tppPrivateKeyStr);
      privateKeyWriter.close();

      JSONArray certChain = jwk.getJSONArray("x5c");
      tppClientCert = certChain.getString(0);
      BufferedWriter clientCertWriter = new BufferedWriter(new FileWriter("client.crt"));
      clientCertWriter.write(toPemString("CERTIFICATE",  java.util.Base64.getMimeDecoder().decode(tppClientCert)));
      clientCertWriter.close();
  }

  public static RSAPrivateCrtKey createCrtKey(BigInteger n, BigInteger e, BigInteger d) throws Throwable {

      BigInteger p = findFactor(e, d, n);
      BigInteger q = n.divide(p);
      if (p.compareTo(q) > 1) {
          BigInteger t = p;
          p = q;
          q = t;
      }
      BigInteger exp1 = d.mod(p.subtract(BigInteger.ONE));
      BigInteger exp2 = d.mod(q.subtract(BigInteger.ONE));
      BigInteger coeff = q.modInverse(p);
      RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(n, e, d, p, q, exp1, exp2, coeff);
      KeyFactory kf = KeyFactory.getInstance("RSA");
      return (RSAPrivateCrtKey) kf.generatePrivate(keySpec);
  }
  • typ: EC - JWT signing keypair emulating QSEALC.

    • Build the private key from x, y, d, and crv
  • Public key: first element of the x5c array in the related publicJwks element.

Extracting private key

private void extractSsaSigningKey(String jwkStr) throws Throwable {
    JSONObject response = new JSONObject(jwkStr);
    JSONObject jwks = response.getJSONObject("privateJwks");
    JSONObject jwk = jwks.getJSONArray("keys").getJSONObject(1);

    ECKey.Builder builder = new ECKey.Builder(Curve.P_256, new Base64URL(jwk.getString("x")), new Base64URL(jwk.getString("y")));
    builder.d(new Base64URL(jwk.getString("d")));

    ecPrivateKey = builder.build().toECPrivateKey();
    ecPrivateKeyKid = jwk.getString("kid");
    jwksPublicUrl = response.getString("publicJwksUrl");

    String tppPrivateKeyStr = toPemString("PRIVATE KEY", ecPrivateKey.getEncoded());
    BufferedWriter privateKeyWriter = new BufferedWriter(new FileWriter("ssa-signing-key.pem"));
    privateKeyWriter.write(tppPrivateKeyStr);
    privateKeyWriter.close();
}

The certificates and keys should be available in PEM format and as a p12 keystore.

Key and certificate management is quite complicated. We recommend using standard libraries, e.g. java.security.Keystore and RestAssured.

Refer to our registration app for details on these procedures.


TPP Registration

In order to access PSD2 APIs, TPPs must register with the account/payment service provider. Registration server a number of purposes:

  • Delivering an API Key & Client Credentials to the TPP (Provided by OP Developer in sandbox)
  • Keeping track of the TPPs using PSD2 APIs
  • Delivering important security information, e.g. JWKS endpoints.

In sandbox as well as in production, the TPP must take the following actions:

  • Build the SSA (Software Statement Assertion) and sign it with a QSEALC/emulated signing key
  • Build the registration JWT, include the signed SSA JWT in it, and sign the registration JWT with the same QSEALC/emulated signing key
  • POST the registration JWT to the API.

Registration call

Registration happens by means of a JSON Web Token (JWT) delivered with a POST call to our TPP registration endpoint.

Making this call requires presenting your QWAC, or the equivalent emulator certificate received from the certificate generation API.

POST /oop-tpp-registration/register-tpp HTTPS/1.1
Host: mtls-apis.psd2-sandbox.op.fi
Content-Type: application/jwt
Accept: application/json
x-api-key: <APP_API_KEY> (Only required in sandbox)

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImEwNDdiZTkwZDkzYTNlZDVlOGZlMjdjZDc2YTYzMWY2MTM0YWI5OTgifQ.eyJpYXQiOjE1MzY3MjU4NzAsImV4cCI6NDY5MjQxODQ3MCwiYXVkIjoiaHR0cHM6Ly9vcC5maS8iLCJqdGkiOiJjZmM4MDg5MC1iNjQyLTExZTgtYjczOC0xNTc0MTU1MmNhZWMiLCJyZWRpcmVjdF91cmlzIjpbImh0dHBzOi8vdGVzdHRwcC5yZWRpcmVjdC51cmwiLCJodHRwczovL3Rlc3R0cHAucmVkaXJlY3QyLnVybCIsImh0dHBzOi8vdGVzdHRwcC5yZWRpcmVjdDMudXJsIl0sImdyYW50X3R5cGVzIjpbImNsaWVudF9jcmVkZW50aWFscyIsImF1dGhvcml6YXRpb25fY29kZSIsInJlZnJlc2hfdG9rZW4iXSwic29mdHdhcmVfc3RhdGVtZW50IjoiZXlKaGJHY2lPaUpGVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0lzSW10cFpDSTZJbUV3TkRkaVpUa3daRGt6WVRObFpEVmxPR1psTWpkalpEYzJZVFl6TVdZMk1UTTBZV0k1T1RnaWZRLmV5SnBjM01pT2lKalptTTNPVE0yTUMxaU5qUXlMVEV4WlRndFlqY3pPQzB4TlRjME1UVTFNbU5oWldNaUxDSnBZWFFpT2pFMU16WTNNalU0TnpBc0ltVjRjQ0k2TkRZNU1qUXhPRFEzTUN3aWFuUnBJam9pWTJaak56a3pOakl0WWpZME1pMHhNV1U0TFdJM016Z3RNVFUzTkRFMU5USmpZV1ZqSWl3aWMyOW1kSGRoY21WZlkyeHBaVzUwWDJsa0lqb2lUM0JsYmtKaGJtdHBibWNnVlc1cGNYVmxJR05tWXpjNU16WXhMV0kyTkRJdE1URmxPQzFpTnpNNExURTFOelF4TlRVeVkyRmxZeUlzSW5OdlpuUjNZWEpsWDNKdmJHVnpJanBiSWxCSlV5SXNJa0ZKVXlJc0lsQkpTVk1pWFN3aWMyOW1kSGRoY21WZmFuZHJjMTlsYm1Sd2IybHVkQ0k2SW1oMGRIQTZMeTlzYjJOaGJHaHZjM1E2T0RnNU9TOHVkMlZzYkMxcmJtOTNiaTlsWTJSellTOXFkMnR6TG1wemIyNGlMQ0p6YjJaMGQyRnlaVjlxZDJ0elgzSmxkbTlyWldSZlpXNWtjRzlwYm5RaU9pSm9kSFJ3T2k4dmJHOWpZV3hvYjNOME9qZzRPVGt2TG5KbGRtOXJaV1F2WldOa2MyRXZhbmRyY3k1cWMyOXVJaXdpYzI5bWRIZGhjbVZmWTJ4cFpXNTBYMjVoYldVaU9pSjBaWE4wTFdOc2FXVnVkQ0lzSW5OdlpuUjNZWEpsWDNKbFpHbHlaV04wWDNWeWFYTWlPbHNpYUhSMGNITTZMeTkwWlhOMGRIQndMbkpsWkdseVpXTjBMblZ5YkNJc0ltaDBkSEJ6T2k4dmRHVnpkSFJ3Y0M1eVpXUnBjbVZqZERJdWRYSnNJaXdpYUhSMGNITTZMeTkwWlhOMGRIQndMbkpsWkdseVpXTjBNeTUxY213aVhTd2ljMjltZEhkaGNtVmZZMnhwWlc1MFgzVnlhU0k2SW1oMGRIQnpPaTh2ZEhCd0xtTnZiU0lzSW05eVoxOXFkMnR6WDJWdVpIQnZhVzUwSWpvaWFIUjBjSE02THk5cWQydHpMbTl3Wlc1aVlXNXJhVzVuTG05eVp5NTFheTl2Y21kZmFXUXZiM0puWDJsa0xtcHJkM01pTENKdmNtZGZhbmRyYzE5eVpYWnZhMlZrWDJWdVpIQnZhVzUwSWpvaWFIUjBjSE02THk5cWQydHpMbTl3Wlc1aVlXNXJhVzVuTG05eVp5NTFheTl2Y21kZmFXUXZjbVYyYjJ0bFpDOXZjbWRmYVdRdWFtdDNjeUlzSW05eVoxOXVZVzFsSWpvaVZHVnpkQ0JVVUZBaUxDSnZjbWRmYVdRaU9pSmpabU0zT1RNMk1DMWlOalF5TFRFeFpUZ3RZamN6T0MweE5UYzBNVFUxTW1OaFpXTWlmUS5TbU1nRXRnRGpCV3BsZ3JpNkRURDR4c0ZEYkVyQmpLQlNYZHdkQjdIRHlvbU5tT2dCS2J6eE5QSF9RUGQ2VGhnTkNjWHQtYmdLTzBxS2l0Zm5UdVFYQSJ9.NFZ8i9pVbkYlHvuBufFZ06YXJozQLh3rJul3rJRYtAs-u6FWyk7AbXSv4Uhu8Ioi4d_Nw1kRNYnmI6iBeLCcq55sLdX4cAUGoWJtPDc0jhmUkDwYuO9RGvETtjic1kdjwP8Kg4u8iiFGZJOy1DXSQmh-HNrgIKjd9Srt85oLfRCqEuoNRrsmiA-lHX2CB3vAmgVVcblm5GoIkGlTg77sGozM28XU15KWAx7eiijcuFBD8vozoUzuJEGsZA5342NcCex42fUz74SK0hRksWNBXR7vZ7oYvCR5uvCetALqMuDDIIFky9bKDeWYEC5Bz_l_nlSJOKnNpFFKBbRJezpsbw

Client Registration Request

The request and ID token objects are always signed with ES256, using your QSEALC or generated signing key.

Structure

{
  "alg": "ES256",
  "typ": "JWT",
  "kid": "a047be90d93a3ed5e8fe27cd76a631f6134ab998"
}
{
  "iat": 1536725870,
  "exp": 4692418470,
  "aud": "https://op.fi/",
  "jti": "cfc80890-b642-11e8-b738-15741552caec",
  "redirect_uris": [
    "https://testtpp.redirect.url",
    "https://testtpp.redirect2.url",
    "https://testtpp.redirect3.url"
  ],
  "grant_types": [
    "client_credentials",
    "authorization_code",
    "refresh_token"
  ],
  "software_statement": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImEwNDdiZTkwZDkzYTNlZDVlOGZlMjdjZDc2YTYzMWY2MTM0YWI5OTgifQ.eyJpc3MiOiJjZmM3OTM2MC1iNjQyLTExZTgtYjczOC0xNTc0MTU1MmNhZWMiLCJpYXQiOjE1MzY3MjU4NzAsImV4cCI6NDY5MjQxODQ3MCwianRpIjoiY2ZjNzkzNjItYjY0Mi0xMWU4LWI3MzgtMTU3NDE1NTJjYWVjIiwic29mdHdhcmVfY2xpZW50X2lkIjoiT3BlbkJhbmtpbmcgVW5pcXVlIGNmYzc5MzYxLWI2NDItMTFlOC1iNzM4LTE1NzQxNTUyY2FlYyIsInNvZnR3YXJlX3JvbGVzIjpbIlBJUyIsIkFJUyIsIlBJSVMiXSwic29mdHdhcmVfandrc19lbmRwb2ludCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODg5OS8ud2VsbC1rbm93bi9lY2RzYS9qd2tzLmpzb24iLCJzb2Z0d2FyZV9qd2tzX3Jldm9rZWRfZW5kcG9pbnQiOiJodHRwOi8vbG9jYWxob3N0Ojg4OTkvLnJldm9rZWQvZWNkc2Evandrcy5qc29uIiwic29mdHdhcmVfY2xpZW50X25hbWUiOiJ0ZXN0LWNsaWVudCIsInNvZnR3YXJlX3JlZGlyZWN0X3VyaXMiOlsiaHR0cHM6Ly90ZXN0dHBwLnJlZGlyZWN0LnVybCIsImh0dHBzOi8vdGVzdHRwcC5yZWRpcmVjdDIudXJsIiwiaHR0cHM6Ly90ZXN0dHBwLnJlZGlyZWN0My51cmwiXSwic29mdHdhcmVfY2xpZW50X3VyaSI6Imh0dHBzOi8vdHBwLmNvbSIsIm9yZ19qd2tzX2VuZHBvaW50IjoiaHR0cHM6Ly9qd2tzLm9wZW5iYW5raW5nLm9yZy51ay9vcmdfaWQvb3JnX2lkLmprd3MiLCJvcmdfandrc19yZXZva2VkX2VuZHBvaW50IjoiaHR0cHM6Ly9qd2tzLm9wZW5iYW5raW5nLm9yZy51ay9vcmdfaWQvcmV2b2tlZC9vcmdfaWQuamt3cyIsIm9yZ19uYW1lIjoiVGVzdCBUUFAiLCJvcmdfaWQiOiJjZmM3OTM2MC1iNjQyLTExZTgtYjczOC0xNTc0MTU1MmNhZWMifQ.SmMgEtgDjBWplgri6DTD4xsFDbErBjKBSXdwdB7HDyomNmOgBKbzxNPH_QPd6ThgNCcXt-bgKO0qKitfnTuQXA"
}
FieldTypeDescription
algstringThe signing algorithm used. Always ES256.
typstringType of the token. Always gets value JWT .
kidstringHints at the key pair used with this signature. Helps the consumer fetch the right public key for validation.
iatnumber / integerThe time at which the JWT was issued. Epoch seconds.
expnumber / integerRequest Expiration time. Epoch seconds.
audstringRequest audience (The ASPSP). Use value OP .
jtistringJWT ID: a unique identifier for the ID. MUST be unique to prevent replay attacks.
redirect_urisarray / stringArray of whitelisted redirection URI strings for use in redirect-based flows (i.e. authorization code).
grant_typesarrayArray identifying the different grant types the TPP will use.
software_statementstring/jwtSSA issued by OpenBanking identifier, JWT format.

Software Statement Assertion

The Software Statement Assertion is a JWT created and signed by the JWT. It is signed with ES256 using your QSEALC or the associated signing key received from OP's certificate generation service.

Recall that if you have generated a certificate, you may use the "publicJwksUrl" in the SSA field software_jwks_endpoint: in other words, you don't need to set up a public JWKS endpoint to get started in the sandbox.

{
  "alg": "ES256",
  "typ": "JWT",
  "kid": "a047be90d93a3ed5e8fe27cd76a631f6134ab998"
}
{
  "iss": "OP-TEST-TPP-354d734d-1273",
  "iat": 1536725870,
  "exp": 4692418470,
  "jti": "cfc79362-b642-11e8-b738-15741552caec",
  "software_client_id": "OpenBanking Unique cfc79361-b642-11e8-b738-15741552caec",
  "software_roles": [
    "PIS",
    "AIS",
    "PIIS"
  ],
  "software_jwks_endpoint": "http://localhost:8899/.well-known/ecdsa/jwks.json",
  "software_jwks_revoked_endpoint": "http://localhost:8899/.revoked/ecdsa/jwks.json",
  "software_client_name": "test-client",
  "software_redirect_uris": [
    "https://testtpp.redirect.url",
    "https://testtpp.redirect2.url",
    "https://testtpp.redirect3.url"
  ],
  "software_client_uri": "https://tpp.com",
  "org_name": "Test TPP",
  "org_id": "OP-TEST-TPP-354d734d-1273"
}
FieldTypeDescription
issstringTPP ID.
iatnumber / integerThe time at which the JWT was issued.
expnumber / integerRequest Expiration Time.
jtistringJWT ID, e.g. 5e63fcae-0c46-4be3-bbf8-eb6eb9bb14a1.
software_client_idstringClient ID of the software client.
software_client_namestringHuman-readable name of the software client.
software_client_uristring / URIWebsite or resource root URI.
software_jwks_endpointstring / URIEndpoint that exposes all active signing and network certs for the software. This field will contain the URI received during certificate generation. When you implement your own JWKS endpoint, ensure that it contains at least two keys: the client certificate for your application (QWAC), and the public key for JWT signature validation (QSEALC). CHECK
software_jwks_revoked_endpointstring / URIEndpoint that contains all revoked JWKs for the software.
software_redirect_urisarray / stringContains all redirect URIs for the software client.
software_rolesarray / stringPSD2 roles this software is authorized to perform.
org_idstringUnique ID for the software creator as assigned by a competent authority. This field contains the TPP ID received from the certificate generation service.
org_namestringLegal Entity Identifier or other known organisation name.

Registration Response

Once successfully registered, you will receive a block of JSON which contains your client information. Store this information well, as it will be required at nearly every step of using PSD2 APIs.

registration: {
    "client_id": "4vPsWdBi56G2dezEmfvh",
    "client_id_issued_at": 1552553405,
    "client_secret": "jqGQqZ66AXahdiMVFj9N",
    "client_secret_expires_at": 0,
    "api_key": "cGY7jn9z8Y141GZWMu6pNlCT0tYlD6PM",
    "client_name": "software-client-1",
    "redirect_uris": [
        "https://localhost:8181",
        "https://tpp-demo-app.prod.psd2-sandbox.aws.op-palvelut.net/oauth/access_token"
    ],
    "grant_types": [
        "client_credentials",
        "authorization_code",
        "refresh_token"
    ],
    "software_id": "atyprodappid",
    "scope": "openid intentcreate accounts payments",
    "jwks_endpoint": "https://example.tpp/jwks.url",
    "software_roles": [
        "AIS",
        "PIS"
    ]
},
ssaSigningKid: DTfeIw
Field NameTypeDescription
client_idstringClient ID of the TPP application.
client_id_issued_atDate / timestampTime of issuance of the client credentials. Seconds since Epoch.
client_secretstringClient secret of the TPP application.
api_keystringAPI Key of the TPP application. In sandbox, this is a replayed value as the API key has already been received from OP Developer.
redirect_urisarray -> string / URIRedirect uris registered to the application.
grant_typesarray -> stringGrant types allowed to the application.
software_idstringSoftware ID of the application.
scopestringSpace-delimited list of scopes allowed to the application. Possible values: AISP, PISP, CBPII.
jwks_endpointstring / URIJWKS endpoint registered to the application.
token_endpoint_auth_methodstringMethod of authentication used when calling the token endpoint. Always gets the value private_key_jwt .
software_rolesarray -> stringLicense-based roles registered to the application.
ssaSigningKeystringKey ID of the signing key contained in the file ssa-signing-key.pem. This key ID is required when signing JWT requests.