Sorry, you need to enable JavaScript to visit this website.

JWS Request for PSD2 Enrollment

Enrollment requests are to be represented in the Flattened JWS JSON Serialization format, as specified in section 7.2.2 of RFC 7515. Below, we provide an example of how a request object may be created. A request object consists of the following components:

  1. Protected (Header)
  2. Payload
  3. Signature

1. Creating the Protected Header

The protected header is required to contain the algorithm and the public certificate obtained from your QTSP. Currently RS256 is the only supported algorithm. The x5c parameter (RFC 7515 section 4.1.6) is expected to contain no more and no less than 1 valid QSeal eIDAS certificate. This needs to be a Base64 encoded DER (NOT URL-safe Base64).

If necessary you can convert PEM certificates to DER format with openssl:

openssl x509 -outform der -in certificatename.pem -out certificatename.der

In the following example, for purposes of illustration only, we instead use a regular X.509 certificate.

PROTECTED = { "alg": "RS256", "x5c": [BASE64(DER_CONTENT)] }

Example:

{ "alg": "RS256", "x5c": ["MIIFeDCCA2ACCQCPCM/Z+y911TANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJOTDERMA8GA1UECgwIUmFib2JhbmsxGDAWBgNVBAsMD1BTRDIgRW5yb2xsbWVudDEeMBwGA1UEAwwVZGV2ZWxvcGVyLnJhYm9iYW5rLm5sMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlQHJhYm9iYW5rLm5sMB4XDTE5MDQwNTE1NDA0OFoXDTIwMDQwNDE1NDA0OFowfjELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFJhYm9iYW5rMRgwFgYDVQQLDA9QU0QyIEVucm9sbG1lbnQxHjAcBgNVBAMMFWRldmVsb3Blci5yYWJvYmFuay5ubDEiMCAGCSqGSIb3DQEJARYTZXhhbXBsZUByYWJvYmFuay5ubDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOAJ9HwtfLbqysVnWbfbSevR8Y4Qubj2JJEzanv3jIi0E2cdtcDa7UgMZiFYzKx3aigsljh4c5+5MKwd9zdjwCR6Jz3s1DaaHluvQZjW3XuL2sg1RbnK4qAkqLie85Nqg4jcV0SIxfbHpbZXqyOlepHVt2qIkniWBfpOylMu2GcTKeBDbF0uWF+Bh6dJ6sUlKf5AgE1w4XWNBuxEE1Oa4Mb7wcAybRdjJpqbGBoZixVzOXgg002pSW7qkQ6tmm/36Z5+7YjZum300gNUXB1bg4NtK/wHAUBqG2CQI7yVWQgXfA+Oxk8qxQLsqvULDpcO53JhFNoYljIqmwlAmmB5aERcG37MBTcE5+akCgPglcc2npq1WGNDkEfMImCsEjl8aSKJlQRFiUJ+rrVPwlXVep189xi70qbm/A972enz8obAL1VlLY8bTtAS9Fv/aligujmQGU8C/LZcQEsGryQyYVgxvEBjPjRCIutYYeQm7B7xZq63YsablJ79I0Fs2fH52sx/OVay4Z3VXOyKOz/sACwznBxmtgwNq1SlMJ0VaWr8fGoQOCU/4RDl360QfsZ2ffCKI6NlVLBvUnoiqdu6necds5zJT0ubvST24K5B7WB/TvKlMuKA3OvbN301tMFCyOOZpMLpRwPcA7Jze75AFTDkWpLSyg7LdOr5yXZMUYqVAgMBAAEwDQYJKoZIhvcNAQELBQADggIBACIkcdAcFGidksywvS+arIPIbbRjwBrA/Mn7dRTKlAeNKz215jig1CBByeWjySU0zghruCw4g6k/1iXOvdrkJ7jY9niDJP9+477tEnwtmFVDi6J52gNmvbBHYLd2UlXU72mEr9LGp1XtgGtm19Nbmdpd60gnRXe4M8XL3SQqCe1p5dtPhDCcdG2jmSHJvlrHPWJr4sROG4iEcLi7Ht7Zk1YMtFs0M7Lbl7X+8xm5QfsrGFARsQQDwBsRy2+P3/q9eJbUIhos4qT8fgt97RYGNea8AVAOUqY+7fs1450VeDKVcGfGHHZS/tgM1G3NwjuizAk9LdhRkNMrCmj4ndAuZngU74H6osGsV34L/zxHZfBI2Gxy5VrH5lhTGX/YqGqHzYoC0FctZ9oIVTuNEhRNFVAVc58N+z11GEfsdOcj+HnCq9HCNP3KIwq60RsRMCvYOf0rmydzaGzz/oKdTtWvcvKt9AY7jgHukms+zYPAeOMOwz92OpK38uj2hRpIfywCEORT51CMm17Nqc4xtOHyvFAHK4ubi5TyMlV4blg30HtOOkWNkCmC51ouLkEtsRsmFFsU+bv/111U6fhAp8Ud7cep+oh06MEFxI1KnZDUF9meS2Jn/uv6Zpa8lySbN78jrjlPni2BEGeiDew1p3pc2U1IygseZZLDeJhoDXJpF3g7"] }

2. Creating the Payload

The payload must contain the email address (ptc_email) and a timestamp in seconds (exp) which indicates until when the request is allowed to be handled.

PAYLOAD = { "ptc_email": "YOUR_EMAIL", "exp": TIMESTAMP_INTEGER }

Example:

{ "ptc_email": "example@rabobank.nl", "exp": 1554080659 }

3. Creating the signature

A signature is created with three elements: a signing string, the public certificate and the private key.

3.1 Signing string

For creating the signing string you need the protected header and the payload. Both elements need to be URL-safe Base64 encoded (RFC 4648) and then concatenated with a period (.) in between.

SIGNING_STRING = BASE64URL(PROTECTED) + "." + BASE64URL(PAYLOAD)

Example:

eyAiYWxnIjogIlJTMjU2IiwgIng1YyI6IFsiTUlJRmVEQ0NBMkFDQ1FDUENNL1oreTkxMVRBTkJna3Foa2lHOXcwQkFRc0ZBREIrTVFzd0NRWURWUVFHRXdKT1RERVJNQThHQTFVRUNnd0lVbUZpYjJKaGJtc3hHREFXQmdOVkJBc01EMUJUUkRJZ1JXNXliMnhzYldWdWRERWVNQndHQTFVRUF3d1ZaR1YyWld4dmNHVnlMbkpoWW05aVlXNXJMbTVzTVNJd0lBWUpLb1pJaHZjTkFRa0JGaE5sZUdGdGNHeGxRSEpoWW05aVlXNXJMbTVzTUI0WERURTVNRFF3TlRFMU5EQTBPRm9YRFRJd01EUXdOREUxTkRBME9Gb3dmakVMTUFrR0ExVUVCaE1DVGt3eEVUQVBCZ05WQkFvTUNGSmhZbTlpWVc1ck1SZ3dGZ1lEVlFRTERBOVFVMFF5SUVWdWNtOXNiRzFsYm5ReEhqQWNCZ05WQkFNTUZXUmxkbVZzYjNCbGNpNXlZV0p2WW1GdWF5NXViREVpTUNBR0NTcUdTSWIzRFFFSkFSWVRaWGhoYlhCc1pVQnlZV0p2WW1GdWF5NXViRENDQWlJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFPQUo5SHd0ZkxicXlzVm5XYmZiU2V2UjhZNFF1YmoySkpFemFudjNqSWkwRTJjZHRjRGE3VWdNWmlGWXpLeDNhaWdzbGpoNGM1KzVNS3dkOXpkandDUjZKejNzMURhYUhsdXZRWmpXM1h1TDJzZzFSYm5LNHFBa3FMaWU4NU5xZzRqY1YwU0l4ZmJIcGJaWHF5T2xlcEhWdDJxSWtuaVdCZnBPeWxNdTJHY1RLZUJEYkYwdVdGK0JoNmRKNnNVbEtmNUFnRTF3NFhXTkJ1eEVFMU9hNE1iN3djQXliUmRqSnBxYkdCb1ppeFZ6T1hnZzAwMnBTVzdxa1E2dG1tLzM2WjUrN1lqWnVtMzAwZ05VWEIxYmc0TnRLL3dIQVVCcUcyQ1FJN3lWV1FnWGZBK094azhxeFFMc3F2VUxEcGNPNTNKaEZOb1lsaklxbXdsQW1tQjVhRVJjRzM3TUJUY0U1K2FrQ2dQZ2xjYzJucHExV0dORGtFZk1JbUNzRWpsOGFTS0psUVJGaVVKK3JyVlB3bFhWZXAxODl4aTcwcWJtL0E5NzJlbno4b2JBTDFWbExZOGJUdEFTOUZ2L2FsaWd1am1RR1U4Qy9MWmNRRXNHcnlReVlWZ3h2RUJqUGpSQ0l1dFlZZVFtN0I3eFpxNjNZc2FibEo3OUkwRnMyZkg1MnN4L09WYXk0WjNWWE95S096L3NBQ3d6bkJ4bXRnd05xMVNsTUowVmFXcjhmR29RT0NVLzRSRGwzNjBRZnNaMmZmQ0tJNk5sVkxCdlVub2lxZHU2bmVjZHM1ekpUMHVidlNUMjRLNUI3V0IvVHZLbE11S0EzT3ZiTjMwMXRNRkN5T09acE1McFJ3UGNBN0p6ZTc1QUZURGtXcExTeWc3TGRPcjV5WFpNVVlxVkFnTUJBQUV3RFFZSktvWklodmNOQVFFTEJRQURnZ0lCQUNJa2NkQWNGR2lka3N5d3ZTK2FySVBJYmJSandCckEvTW43ZFJUS2xBZU5LejIxNWppZzFDQkJ5ZVdqeVNVMHpnaHJ1Q3c0ZzZrLzFpWE92ZHJrSjdqWTluaURKUDkrNDc3dEVud3RtRlZEaTZKNTJnTm12YkJIWUxkMlVsWFU3Mm1FcjlMR3AxWHRnR3RtMTlOYm1kcGQ2MGduUlhlNE04WEwzU1FxQ2UxcDVkdFBoRENjZEcyam1TSEp2bHJIUFdKcjRzUk9HNGlFY0xpN0h0N1prMVlNdEZzME03TGJsN1grOHhtNVFmc3JHRkFSc1FRRHdCc1J5MitQMy9xOWVKYlVJaG9zNHFUOGZndDk3UllHTmVhOEFWQU9VcVkrN2ZzMTQ1MFZlREtWY0dmR0hIWlMvdGdNMUczTndqdWl6QWs5TGRoUmtOTXJDbWo0bmRBdVpuZ1U3NEg2b3NHc1YzNEwvenhIWmZCSTJHeHk1VnJINWxoVEdYL1lxR3FIellvQzBGY3RaOW9JVlR1TkVoUk5GVkFWYzU4Tit6MTFHRWZzZE9jaitIbkNxOUhDTlAzS0l3cTYwUnNSTUN2WU9mMHJteWR6YUd6ei9vS2RUdFd2Y3ZLdDlBWTdqZ0h1a21zK3pZUEFlT01Pd3o5Mk9wSzM4dWoyaFJwSWZ5d0NFT1JUNTFDTW0xN05xYzR4dE9IeXZGQUhLNHViaTVUeU1sVjRibGczMEh0T09rV05rQ21DNTFvdUxrRXRzUnNtRkZzVStidi8xMTFVNmZoQXA4VWQ3Y2VwK29oMDZNRUZ4STFLblpEVUY5bWVTMkpuL3V2NlpwYThseVNiTjc4anJqbFBuaTJCRUdlaURldzFwM3BjMlUxSXlnc2VaWkxEZUpob0RYSnBGM2c3Il0gfQ.eyAicHRjX2VtYWlsIjogImV4YW1wbGVAcmFib2JhbmsubmwiLCAiZXhwIjogMTU0MDgwNjU5IH0

3.2 Signing algorithm

Use the QSeal eIDAS certificate and its corresponding private key to sign the string using RSA SHA256:

SIGNATURE = RSA_SHA256(
    SIGNING_STRING,
    PUBLIC_CERTIFICATE,
    PRIVATE_KEY
)

4. Creating the API request body

Finally create the body of the API request by URL-safe Base64 encoding (RFC 4648) each part of the JWS:

{
    "protected": BASE64URL(PROTECTED),
    "payload":   BASE64URL(PAYLOAD),
    "signature": BASE64URL(SIGNATURE)
}

Example:

{
    "protected": "eyAiYWxnIjogIlJTMjU2IiwgIng1YyI6IFsiTUlJRmVEQ0NBMkFDQ1FDUENNL1oreTkxMVRBTkJna3Foa2lHOXcwQkFRc0ZBREIrTVFzd0NRWURWUVFHRXdKT1RERVJNQThHQTFVRUNnd0lVbUZpYjJKaGJtc3hHREFXQmdOVkJBc01EMUJUUkRJZ1JXNXliMnhzYldWdWRERWVNQndHQTFVRUF3d1ZaR1YyWld4dmNHVnlMbkpoWW05aVlXNXJMbTVzTVNJd0lBWUpLb1pJaHZjTkFRa0JGaE5sZUdGdGNHeGxRSEpoWW05aVlXNXJMbTVzTUI0WERURTVNRFF3TlRFMU5EQTBPRm9YRFRJd01EUXdOREUxTkRBME9Gb3dmakVMTUFrR0ExVUVCaE1DVGt3eEVUQVBCZ05WQkFvTUNGSmhZbTlpWVc1ck1SZ3dGZ1lEVlFRTERBOVFVMFF5SUVWdWNtOXNiRzFsYm5ReEhqQWNCZ05WQkFNTUZXUmxkbVZzYjNCbGNpNXlZV0p2WW1GdWF5NXViREVpTUNBR0NTcUdTSWIzRFFFSkFSWVRaWGhoYlhCc1pVQnlZV0p2WW1GdWF5NXViRENDQWlJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFPQUo5SHd0ZkxicXlzVm5XYmZiU2V2UjhZNFF1YmoySkpFemFudjNqSWkwRTJjZHRjRGE3VWdNWmlGWXpLeDNhaWdzbGpoNGM1KzVNS3dkOXpkandDUjZKejNzMURhYUhsdXZRWmpXM1h1TDJzZzFSYm5LNHFBa3FMaWU4NU5xZzRqY1YwU0l4ZmJIcGJaWHF5T2xlcEhWdDJxSWtuaVdCZnBPeWxNdTJHY1RLZUJEYkYwdVdGK0JoNmRKNnNVbEtmNUFnRTF3NFhXTkJ1eEVFMU9hNE1iN3djQXliUmRqSnBxYkdCb1ppeFZ6T1hnZzAwMnBTVzdxa1E2dG1tLzM2WjUrN1lqWnVtMzAwZ05VWEIxYmc0TnRLL3dIQVVCcUcyQ1FJN3lWV1FnWGZBK094azhxeFFMc3F2VUxEcGNPNTNKaEZOb1lsaklxbXdsQW1tQjVhRVJjRzM3TUJUY0U1K2FrQ2dQZ2xjYzJucHExV0dORGtFZk1JbUNzRWpsOGFTS0psUVJGaVVKK3JyVlB3bFhWZXAxODl4aTcwcWJtL0E5NzJlbno4b2JBTDFWbExZOGJUdEFTOUZ2L2FsaWd1am1RR1U4Qy9MWmNRRXNHcnlReVlWZ3h2RUJqUGpSQ0l1dFlZZVFtN0I3eFpxNjNZc2FibEo3OUkwRnMyZkg1MnN4L09WYXk0WjNWWE95S096L3NBQ3d6bkJ4bXRnd05xMVNsTUowVmFXcjhmR29RT0NVLzRSRGwzNjBRZnNaMmZmQ0tJNk5sVkxCdlVub2lxZHU2bmVjZHM1ekpUMHVidlNUMjRLNUI3V0IvVHZLbE11S0EzT3ZiTjMwMXRNRkN5T09acE1McFJ3UGNBN0p6ZTc1QUZURGtXcExTeWc3TGRPcjV5WFpNVVlxVkFnTUJBQUV3RFFZSktvWklodmNOQVFFTEJRQURnZ0lCQUNJa2NkQWNGR2lka3N5d3ZTK2FySVBJYmJSandCckEvTW43ZFJUS2xBZU5LejIxNWppZzFDQkJ5ZVdqeVNVMHpnaHJ1Q3c0ZzZrLzFpWE92ZHJrSjdqWTluaURKUDkrNDc3dEVud3RtRlZEaTZKNTJnTm12YkJIWUxkMlVsWFU3Mm1FcjlMR3AxWHRnR3RtMTlOYm1kcGQ2MGduUlhlNE04WEwzU1FxQ2UxcDVkdFBoRENjZEcyam1TSEp2bHJIUFdKcjRzUk9HNGlFY0xpN0h0N1prMVlNdEZzME03TGJsN1grOHhtNVFmc3JHRkFSc1FRRHdCc1J5MitQMy9xOWVKYlVJaG9zNHFUOGZndDk3UllHTmVhOEFWQU9VcVkrN2ZzMTQ1MFZlREtWY0dmR0hIWlMvdGdNMUczTndqdWl6QWs5TGRoUmtOTXJDbWo0bmRBdVpuZ1U3NEg2b3NHc1YzNEwvenhIWmZCSTJHeHk1VnJINWxoVEdYL1lxR3FIellvQzBGY3RaOW9JVlR1TkVoUk5GVkFWYzU4Tit6MTFHRWZzZE9jaitIbkNxOUhDTlAzS0l3cTYwUnNSTUN2WU9mMHJteWR6YUd6ei9vS2RUdFd2Y3ZLdDlBWTdqZ0h1a21zK3pZUEFlT01Pd3o5Mk9wSzM4dWoyaFJwSWZ5d0NFT1JUNTFDTW0xN05xYzR4dE9IeXZGQUhLNHViaTVUeU1sVjRibGczMEh0T09rV05rQ21DNTFvdUxrRXRzUnNtRkZzVStidi8xMTFVNmZoQXA4VWQ3Y2VwK29oMDZNRUZ4STFLblpEVUY5bWVTMkpuL3V2NlpwYThseVNiTjc4anJqbFBuaTJCRUdlaURldzFwM3BjMlUxSXlnc2VaWkxEZUpob0RYSnBGM2c3Il0gfQ",
    "payload": "eyAicHRjX2VtYWlsIjogImV4YW1wbGVAcmFib2JhbmsubmwiLCAiZXhwIjogMTU0MDgwNjU5IH0",
    "signature": "wHAILEDbUN1RnGVnNGV_flHm35SC_AojfUUpep_IgOO1l6SkE2Zo3bk7VMnW64R74ksSl5Sp2dFa52iGOKgtZK5JUF3s5tuy5fuRMoTgW5qWH9WFFa2HSjpAEzJolU38vJtrQsdxxIR-AbrGVZoGR0f07e_lzxqqMCzBgTLT3p-ADuzJQ7jJoCvbVEVsc0HPtcT9UdLU87p3qb-j21QjYrN3R-pL7I5tuPBcP9G_xcmF9HZY92aWVzME-KfVWI1OKUeacvvGeKq7d_k6yPiFyUatJltEoHXjRkO1ViQBTIhbNjq_tWGkI2Q6El0kghDEQ6OE5ro7FmMlXBXOCGFAYlhA7xIPA4FgEb8CJ2tbRHk7Q4sOsR04GFx9EUKZBhEejF_DkZ-w0VdiAN_yOZmLZQvzUnSab7jw6e7ptVvsP7OEtXArydKKXIa5mUccsFTL4yAw6MjPttw41bnwcTLfqHYci3Pz1ROSAWAhMWr_ce0kwOc3752qA8k3GHnZPt8voBQG0BrH-c10ruhREtdskhcm7FSQU-vi9AjcJ_gyS7EK5qAyaWrzLmvd8aqH605HHmOBb3EkYJERDCm_NG3LCpd-ZmzT6th2kMWWsCVG_GNO_1pZh9rr5-_jMuGpOlrXwqRb2dT_Sb_m3hFuLJSDV6VCUk-aird8eELa-GtweMI"
}