Signed responses
JWS tokens can be generated by our API instead of JSON responses. It can be very beneficial if you or your customers need to affirm the data’s origin (it guarantees data was not altered), which request was used or the timestamp of the request execution.
💡 Information: Signed responses are not enabled by default. Please contact us if you’re interested in this feature.
Request signed responses
You just need to add the following parameter to your requests to get a signed response:
# query parameter
sign_response=true
JWS Token format
The JWS token our API return follow this structure:
{
"token": "header.payload.signature"
}
First we have the header:
It contains information about the signature process (it is a base64-encoded JSON).
See the token signature verification process below.
{
"kid": ...,
"typ": ...,
"key_url": ...,
"alg": ...,
}
Second we have the payload:
It is a base64-encoded JSON with the following structure.
{
"request_url": ...,
"response_timestamp": ...,
"response_payload": ...,
}
Finally we have the signature:
- It is a base64-encoded bytes section.
Verify token signature
- Get the
key_url
, found in theheader
part.- You must verify that this key is hosted on a trusted host, for example
oxlin.io
.
- You must verify that this key is hosted on a trusted host, for example
- Retrieve the public key using the
GET /sign-keys
endpoint (see below)- You will find in the result a key with the key
kid
found in the header.
- You will find in the result a key with the key
- A key may be deprecated.
- When that’s the case, the
deprecated
field is set and its value is the date and time of the deprecation. - Any signature made with a deprecated key should not be trusted.
- If the
deprecated
field isnull
or missing, the signature can be verified.
- When that’s the case, the
- Use the
public_key
field to check the signature.
Keys resources
List all keys
GET /sign-keys
The response looks like this:
[
{
"public_key": ...,
"id": ...,
"deprecated": ...,
},
{
"public_key": ...,
"id": ...,
}
]
Get a key
GET /sign-keys/{key_id}
The response looks like this:
{
"public_key": ...,
"id": ...,
}
Keys resources
Property | Mandatory | Type | Description |
---|---|---|---|
id | yes | String | UniqueID of the key. |
public_key | yes | String | PEM of the public key. |
deprecated | no | DateTime ISO 8601 extended format is used or null | If set, this key is deprecated and any signature using it should not be trusted. |
Full exemple
Request signed responses
The first step is to use one of our endpoints with query parameters sign_response=true
.
In our case we will use the following endpoint: "http://sandbox-api.oxlin.io/v2.1/accounts/111865?sign_response=true"
The response we get is:
Token Base 64
{"token":"eyJ0eXAiOiJKV1QiLCJraWQiOiJzaWcuYXBpLm94bGluLmlvIiwiYWxnIjoiUlM1MTIiLCJrZXlfdXJsIjoiaHR0cDpcL1wvc2FuZGJveC1hcGkub3hsaW4uaW9cL3NpZ24ta2V5c1wvc2lnLmFwaS5veGxpbi5pbyJ9.eyJyZXF1ZXN0X3VybCI6Imh0dHA6XC9cL3NhbmRib3gtYXBpLm94bGluLmlvXC92Mi4xXC9hY2NvdW50c1wvMTExODY1P3NpZ25fcmVzcG9uc2U9dHJ1ZSIsInJlc3BvbnNlX3RpbWVzdGFtcCI6MTY3ODI3ODY5MCwicmVzcG9uc2VfcGF5bG9hZCI6eyJhY2NvdW50X251bWJlciI6IlBFQTIzNDQ1NjY1Iiwic3RhdHVzIjoiQUNUSVZFIiwibmFtZSI6IlBFQTIzNDQ1NjY1ICh4NTY2NSkiLCJ1c2FnZSI6IlBFUlNPTkFMIiwidHlwZSI6IlNBVklOR1MiLCJpZCI6IjExMTg2NSIsImNyZWF0aW9uX2RhdGUiOjE2NzgyNzg0MTYsInNhdmluZ3MiOnsiY2FwaXRhbF9nYWluIjp7ImFtb3VudCI6LTU2OTksInBlcmNlbnQiOi00LjJ9LCJzYXZpbmdzX3R5cGUiOiJTSEFSRVMiLCJ0eXBlIjoiUEVBIiwiZWZmZWN0X2RhdGUiOjEyODcyNjY0MDAsImludmVzdGVkX3JhdyI6MTM1NTY4fSwibGFzdF9jaGFubmVsX2RlZmluaXRpb25faWQiOiI4NzAwIiwiY3VycmVuY3kiOiJFVVIiLCJjb25uZWN0aW9uX2lkIjoiNjAxMzciLCJiYWxhbmNlX2RhdGUiOjE2NzgyNzg0MTgsImJhbGFuY2UiOjkwMTkwfX0.gSkdGA7tGuxZF0olRY-48jSBtBkthDHw74GJ8PeXlNtACYg0oNBEd9LUh2BF9p3Y7s3puQL6N-F_BehmL62ZOx8qgYFgL9cwldfnaTdBkWk9KsARdIzxiqTA2t9k_4N8n8GMUrsF5w_lenJcxzZAyX1NKBsVFwgDrxNf46TFUySPuT7h_55K1yLFrTi2L2PewtT1H3zG0mYVyI8FMl9kwS-AyyeTQ6kTtfYN0utJS23JFE8bhTFHzx5usgh6wDapUqldeLdHIUWdrrJgETCSeZ8jH9m2JKQQ1itGI8wqnO5Xlv5m6GitovdEPgN3DpbZ0EsogGncXMn-U3mzUXJXfpM97liUBuVWP0I9I51iftJLYgSBKbv0fl7kRXotyn-1-njMSE_ABjdxg_CPYbf0_U4f6I4H6-eFe27MYVWOGkyXKoBnkM6fsPnc4F1MC2IrMXFE3Fym_7pUVEw3NpMwd4kh-BtQOYIxpt9kOEb0O2AIKUQVMNaZ608U-AIdYkN22QSvLeoOh3JxVE7fQdWXRyJRzP1cw_V3dvqkdSpg7nIx2UCfhXsQ95HP96f3l26zGrNeZP85HuTJftTSLpIWx47CpJu4Lu2KEGvj5FhIIzmSakIAnduHDkfsieKWkNuUaChNuGVJLZf9lgPRYCv6XEy1nFA1uNrdrgFRerqZgNI"}
JWS Token format
We are now going to decode the token obtained previously.
Here is the content once the token is decoded.
- Header part
{
"kid": "sig.api.oxlin.io",
"typ": "JWT",
"key_url": "http://sandbox-api.oxlin.io/sign-keys/sig.api.oxlin.io",
"alg": "RS512"
}
- Payload part
{
"request_url": "http://sandbox-api.oxlin.io/v2.1/accounts/111865?sign_response=true",
"response_timestamp": 1678278690,
"response_payload": {
"account_number": "PEA23445665",
"status": "ACTIVE",
"name": "PEA23445665 (x5665)",
"usage": "PERSONAL",
"type": "SAVINGS",
"id": "111865",
"creation_date": 1678278416,
"savings": {
"capital_gain": {
"amount": -5699,
"percent": -4.2
},
"savings_type": "SHARES",
"type": "PEA",
"effect_date": 1287266400,
"invested_raw": 135568
},
"last_channel_definition_id": "8700",
"currency": "EUR",
"connection_id": "60137",
"balance_date": 1678278418,
"balance": 90190
}
}
Verify token signature
The first step will be to retrieve the value of the “key_url” key in the header.
You must verify that the signature key is hosted on a trusted host, for example oxlin.io.```bash
http://sandbox-api.oxlin.io/sign-keys/sig.api.oxlin.io
```The second step will be to use the “GET KEY” endpoint to retrieve the public_key, the id match with the “kid” field in the header.
- It will look like this:
{
"public_key":"-----BEGIN PUBLIC KEY-----
BIGOAjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAs1KDiMH4B/Jajmp27+kq
dhGXH6TX2bDYBAQFQ1nBa2mgLxzRDc4ehsMOuXr47MZ8LjqSVZA9b3kIP+IdtRzV
i6TMxUwjhYQgzxZCWXmGE1LHYBuwt7og9JJ6g2L73DC4Ly6Y8ixM2k8RFBubnN+K
7fL7tUv9bPlsuzhSH3hx7jsksO9lsjKe7pMlFNNvtSTl/+bqQ2h8C+O6cBTbSLUX
lUNLwZt7SJaLd8e4Mox3jP0Rpyziqi0+4GM1b9cllm7O5T//qd6m0fzdbOAhngYT
kfpcKQXS7c4/QkV+Mk9mt9t3N+MSw0E8dyrUfQiY0SLXxUPkXwhwHD5+OV34cdFs
iUV47uGmZtiJKQYrW5tA2duE8rFDhezdumsNzuzyTSHjsjzU3spoqj4Tyni98GKe
vlGamhDlLT54dvDlx58+/wnZIHUI8rY1SIZ6q0c7O3gDtyCdMniinMwO+lfeiumi
dWq+TOK16NKb4Eu/4vWF+f/nuwfPY0fFl7BDzH7UYoMP2lGeQ0jkE728OnHXpN+w
Ch4Gpi4YRnbYF9Qtr/64RvFkCTGLkXe3dqgPj52JHznsOYUXix4WCt872jmWk970
1hW/dzdzfzueuueuDUsjz+PvMuQBhXNDqFg4sdzVWVeJmAXOtseSxvMZPnPECWJE
fYY74VY/qVFXGpt+iGnLPSOXI2skX==
-----END PUBLIC KEY-----",
"id":"sig.api.oxlin.io"
}
- It will look like this:
The third step is to check if the deprecated field is present.
- Make sure that the deprecated field is not present.
- If it’s still present we have a public key which is not valid.
- exemple:⬆️ ⬆️
{
"public_key":"-----BEGIN PUBLIC KEY-----
BIGOAjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAs1KDiMH4B/Jajmp27+kq
dhGXH6TX2bDYBAQFQ1nBa2mgLxzRDc4ehsMOuXr47MZ8LjqSVZA9b3kIP+IdtRzV
i6TMxUwjhYQgzxZCWXmGE1LHYBuwt7og9JJ6g2L73DC4Ly6Y8ixM2k8RFBubnN+K
7fL7tUv9bPlsuzhSH3hx7jsksO9lsjKe7pMlFNNvtSTl/+bqQ2h8C+O6cBTbSLUX
lUNLwZt7SJaLd8e4Mox3jP0Rpyziqi0+4GM1b9cllm7O5T//qd6m0fzdbOAhngYT
kfpcKQXS7c4/QkV+Mk9mt9t3N+MSw0E8dyrUfQiY0SLXxUPkXwhwHD5+OV34cdFs
iUV47uGmZtiJKQYrW5tA2duE8rFDhezdumsNzuzyTSHjsjzU3spoqj4Tyni98GKe
vlGamhDlLT54dvDlx58+/wnZIHUI8rY1SIZ6q0c7O3gDtyCdMniinMwO+lfeiumi
dWq+TOK16NKb4Eu/4vWF+f/nuwfPY0fFl7BDzH7UYoMP2lGeQ0jkE728OnHXpN+w
Ch4Gpi4YRnbYF9Qtr/64RvFkCTGLkXe3dqgPj52JHznsOYUXix4WCt872jmWk970
1hW/dzdzfzueuueuDUsjz+PvMuQBhXNDqFg4sdzVWVeJmAXOtseSxvMZPnPECWJE
fYY74VY/qVFXGpt+iGnLPSOXI2skX==
-----END PUBLIC KEY-----",
"id":"sig.api.oxlin.io",
"deprecated": "2023-02-21T15:24:29.987Z"
}
NOT GOOD
The 4th step is to verify using the public_key that the signature is verified and valid.