Python Code Example

Introduction

Signing request is not hard, but it can be tricky if you don't understand the core concepts. That's why we provide example on how to implement this in Python. We'll do the following:

  • Get a API key

  • Get a Session, device and Installation on sandbox

  • Get the monetary account and add some money

  • Create a signature

  • Use the signature to create a payment.

Copy the files for FastAPI, bunq_lib and signing

What are we trying to achieve

Eventually we make an API call to create a payment. This is because this is one of the calls that requires us to generate a signature.

What is a signature?

A signature is nothing more than a string of characters, but the exact string depends on what you use as input.

To give an example. Let's assume we want to sign the following payload:

{"hello":"World}

And now assume our signature for that payload is Signature: fafd6dad81f90a2d6f7d60a635f206188a54039ba07a84757cf9daf24a60b57a

bunq's backend can verify that that signature indeed belongs to that payload. Based on the public key that we shared earlier.

How does this protect us?

If some attacker would send a different payload:

then that signature would change, and thus not be valid. A malicious attacker will also not be able to recreate a signature of his own, because they do not have our private_key.pem.

Getting started

we'll use the FastAPI framework. And will need FastApi, Cryptography and

We can install these by running: pip install cryptography fastapi uvicornWe'll have the following File structure

Let's create the main.py file first:

This is a quick scaffold that allows us to trigger actionts by visiting a endpoint in your browser.

This file will not run on its own yet. We need the other files too.

Some things to note:

  • You can see the bunq sandbox API key if you don't have one yet get yours here API Keys

  • You see we instantiate the Class BunqClient that we imported from `the lib.bunq_lib`

  • You'll only have to run `uvicorn main:app --reload to start the server

Let's add signing.py

get the full files here

We do this in a few steps:

1 is adding the imports and writing a function that generates the RSA Key pair for us (The function in the example is set up to check if one is generated first, if it is it loads the existing one)

The most important function in the signing.py file is our sign_data() function that actually uses the generated keys and data we want to sign. Pay special attention to the specified hash and padding functions

We can call this function from our bunq_lib.py to generate a signature for each request we want to sign.

Ok now let's make this in bunq_lib.py

We start with the imports and creating a class, with variables for API keys, tokens and everything else we need. You can also see the 2 functions one to generate a device token, and one to load it if it already exists.

Creating installation, registering the device and getting a session

In the same file as above we add a few more functions that allow us to create a installation, device and session

At this point your you could run the fastapi server with the command

That will start the server and will register your device and create the private and public keys. Your file tree should now look like this

Given that we now have a session and can make calls we can finish the rest of our file.

Let's make a payment and a request

In the rest of the file you can see 2 methods 1. request. This is just a generic function that can create a API call to a endpoint of your choosing.

  1. The second function is to create a payment. This one is a bit more tricky as it requires us to sign.

Making a generic API call

In our main.py file we started a fastAPI server which has 2 endpoints 1. /get_cards - Which returns the cards 2. /monetary-account which returns the monetary accounts of the user.

You can see they both use the .request() method that we defined in the bunq_lib.py. They just call a different endpoint.

If we go to our browser and type: http://localhost:8000/monetary_account

We'll get the response object with all our monetary accounts:

Now let's also make a payment:

The set up is the same we simply navigate to: http://localhost:8000/payment to trigger the call to the endpoint

and get a response with the payment ID:

Let's go through it step-by step. To explain the signing in depth.

When we go to the /payment route we trigger this code:

This calls the create_payment() function from the bunq_client class in our bunq_lib.py file. It sends along some payment details, like the receiver IBAN, the monetary account to pay from, a description and an amount.

Now what happens in the create_payment() function

  1. We first create a payload. We have to be very specific in the exact formatting of the payload. That's why we specify the separators. We do this to ensure the payload that we sign and the payload that we send with the request match exactly. Else the signature will fail.

  2. Now we call the sign_data() function from our signing.py file this will return a signature based on our private key and the payload.

  3. We add that signature to our 'X-Bunq-Client-Signature'.

  4. From there it is exactly like any API call where you wait for a 200 response status

  5. We included 1 final step which is to also validate the 'X-Bunq-Server-Signature' signature. by calling the verify_response() function and comparing the signature bunq returned to the public key we stored in the installation step.

Last updated

Was this helpful?