Verify consent in a data source
Introduction
An application registered on the dataspace can request a consent from a user to access the data from a data source which requires user consent. If the user gives the consent the application will get back a consent token and can include it in the X-Consent-Token header when making the request to the product gateway. The product gateway will forward the header to the productizer. This guide explains how the productizer should verify the token if it wants to ensure the user has given their consent.
The consent token is a JSON Web Token (JWT) that can be decoded and verified. This guide will explain in more detail the process of extracting, decoding and verifying it.
For more details on how to request a consent and obtaining a consent token, check out the Using Consent section of the How to build an application guide.
Verifying the consent token in the productizer
Get the X-Consent-Token header
The productizer or data source needs to first extract the consent token from the X-Consent-Token HTTP header of the request. Please note that the header is in many data source definitions optional, so take that into account.
Reading the consent token
The consent token is a JSON Web Token (JWT).
If you are unfamiliar with JWTs you might want to check out the JSON Web Token Introduction. The same site has a really good tool for decoding JWTs directly in the web browser at jwt.io, as well as a fairly good list of different JWT libraries for different programming languages.
You most likely want to use one of the libraries for your programming language rather than try to implement it according to the RFC 7519.
Let's have a look at a valid example token from one of the applications on the sandbox Dataspace and how to verify it.
Let's examine this token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsInYiOjAuMSwidGlkIjoiNzU2YWZjY2MtYjI4ZS00MDY1LTg5NDgtMzhhN2Y2Nzg3NDdmIiwiamt1IjoiaHR0cHM6Ly9jb25zZW50LnNhbmRib3guaW94aW8tZGF0YXNwYWNlLmNvbS8ud2VsbC1rbm93bi9qd2tzLmpzb24iLCJraWQiOiJlMTg3ODVhN2UxMGUxYmQ4YjgzZjM3YmQ0YmUyYzBlNyJ9.eyJzdWIiOiJaR1Z0YjBCMFpYTjBaWEl1YVc5NGFXOHVZMjl0IiwiaXNzIjoiaHR0cHM6Ly9jb25zZW50LnNhbmRib3guaW94aW8tZGF0YXNwYWNlLmNvbSIsImlhdCI6MTY3MjgzNjUzMiwiZXhwIjoxNjcyOTIyOTI1LCJkc2kiOiJkcHA6Ly9pb3hpbzp2MkBzYW5kYm94LmlveGlvLWRhdGFzcGFjZS5jb20vZHJhZnQvQ29tcGFueS9TaGFyZWhvbGRlcnMiLCJzdWJpc3MiOiJodHRwczovL2xvZ2luLnNhbmRib3guaW94aW8tZGF0YXNwYWNlLmNvbSIsImF1ZGlzcyI6IjgzZDU1MTI2LWU2MTctNDNkYy1hMmZmLTQzZmJlYjg0OGNkMSJ9.w7L4Cs0f9fkaohK4IFxsMlIVmZcNqeV77K_8KrZLZDIpKKBbxVycLd02X1cXwqoiKcLclfatBAvcVm8EGtRE60UBRmhy1HQkVCaJ_Q0gCCBqWOPHOGKtpr5KEUj-QgUUMWmN9x64SPLt-VdmRDQHppXcNoeO1YUS5irOtypoOi4R1ri39EXK_aMMPpj9khYbKQdZS4oNnfZ0WgLTmsXk2u9ALw8cq8hFUaCQIHpK4Hddxsmb1gM7DwNU25qCAwmOrrZOvv9P4lVsY1ycYAv_hQa1VIwhCIH4a9Oxajy9ZsF_PZ9ftJZSCwQYknHu5x1pH2wnRJaYsDydFez5K9zFDRsoQ4uVKGj6Fk8W5U5WniE1vVXqmG1wXQ_PB41rAqVvXjs-uoCCwv7pU_E6t382MiGd94rI9AEKXFsq3tV_94HxipNI-tblEUyaocI0CDJM2WkVpij_PHdnRKVR67vWWt_CagqfL39IdwhAqMNhD2mEKwbhCvdlaAAHjT3hSW5xBgnd8Js9Ffe5yekwu-B_eTBkyAVCRfykWFrKQXeMav7G6Ls6oCcN56QYXBgno7y8SA-6ewcnVmvU54kLQOu54AS_nc0NLrDK1P44ipaNh5Kce-LkmJGYQiWYlEo_rGgQgCSZuvXw2dxuzPDB7xxjLgEWMGmjoLmVTFPnZ6IlE68
Please note that tokens are security sensitive and should not be passed into untrustworthy tools or shared with other people in general. The token used here is from a demo application where anyone can log in with a fake username and no password, so anyone could have acquired this token.
At the time you are reading this guide the token will unfortunately have expired, so some of the verifications we will perform here won't work. However you can log in to the MyCompany Demo App and extract your own id_token from a cookie with that name once you've logged in. You can then follow the cURL examples in the Request consent section of the How to build an application guide using that id_token and request the consent. Note that if you need to verify the consent in the browser, you will have to add a returnUrl query parameter to the verifyUrl you get back. You can for example just append ?returnUrl=https://example.com to the returnUrl to be redirected to https://example.com when you've granted the consent. Alternatively you can use the MyCompany Demo App to request and grant the consent and then use the cURL based commands with the id_token to get the consent token directly as shown in the Request the consent token section.
This is what the content of the above token looks like:
Many JWT libraries also allow you to read the JWT without verifying it. In case your library for some reason does not do that, you can actually note that the token consists of three sections separated by a dot, like AAA.BBB.CCC. The first section is the header, the second one the body and the last one the signature. The first two are actually just Base64 encoded JSON strings that can be easily decoded and read, without verifying the signature.
Find the JWKS URI
The first step to find the key is to check the issuer of the token, which is found in the iss field in the body.
Please note that you should check that the iss is one you want to trust. In a typical IOXIO dataspace this would always be the address of the consent provider of the dataspace.
In this example the iss (Issuer) is https://consent.sandbox.ioxio-dataspace.com, which is the consent provider of the sandbox dataspace. The consent provider has a configuration in a well-known path (inspired by the OpenID Connect configuration). The configuration for a consent provider can be found in the path /.well-known/dataspace/consent-configuration.json relative to the iss. Thus in this case the consent provider configuration can be fetched from https://consent.sandbox.ioxio-dataspace.com/.well-known/dataspace/consent-configuration.json. At the time of writing this it returned this JSON content (formatted for readability):
{
"issuer": "https://consent.sandbox.ioxio-dataspace.com",
"jwks_uri": "https://consent.sandbox.ioxio-dataspace.com/.well-known/jwks.json",
"consent_request_uri": "https://consent.sandbox.ioxio-dataspace.com/Consent/Request"
}
The jwks_uri specify where we can find the keys of this consent provider.
For convenience the JWT token also contains the jku (JSON Web Key Set URL) header with the same value. This is what for example jwt.io uses to fetch the key to verify the signature of the token.
Please note that you should validate the iss or jku match what you expect to find on the dataspace you are working on before fetching keys to ensure they are indeed keys that should be trusted on the particular dataspace.
Find the key
At the time of writing this, the jwks_uri https://consent.sandbox.ioxio-dataspace.com/.well-known/jwks.json returned this JSON content (formatted for readability):
{
"keys": [
{
"kid": "e18785a7e10e1bd8b83f37bd4be2c0e7",
"kty": "RSA",
"use": "sig",
"alg": "RS256",
"n": "0FqQHSRgUzu9WwyUnl4FiXADIDptF82eUn1IeOFWt-ZHVzzddsZjT_F7YOZsgVyF9QRc1ROqqnvEs7J90fBQG8nMAml1R56lZdruqqyQ8kAQjqplhi4CAU6NZrzBWybCkZVq6PSvgtHJWSMCcU-09g24Q3GLWvW-gqAh4sZMjf1l45MASjgaYYozaZv1HgeG-dmFOsngafNQue8DGt97UxdqtP3rsjqdKaXR9iPIxcgJNhAQrqTorCiKp_CXUatsHgFD6ANxfgu6iSmBPbgmGi6AhPuAalWTi5BcSWEgawnq_kYopnHH7ymgVjV-6eNmdpyHZ-qaK2k-YB1ydvbdZfbmjl-ybN7YZ5QlXuOnLNHE4eqA1Z5yk0M4eL8smDpH4Mh6dataXxZxp5QkBV9iS7WPHLvWwiOQrOjL0REQ0bSz5d6nfQdjp0wVWQZH0GPQUOwVfqXcMODZAdG1X8d6VhgjG3oTYgDyovCWoG1CJEokLMXrSa-o0Hw_TVgYFbPhwDsxl7KvJDD6cid1sWiYY67isuWWHG7q_QLoG1gTVXIE5ycVzSqVED_bOzxKmorrj4G-XoDyx36mK1O5ROVktJ6dZ7nLJGsWRTzPjXWXMG639snzIClG9momA1fpc6f2vyQsjY-9Gel2toxeQite0hTmUn9-vfWi3mnqFlr-ZaU",
"e": "AQAB"
}
]
}
Use the key entry with a kid (Key ID) and alg (Algorithm) matching the values in the consent token and has the use set to sig (signing). You can read more about JWKS in RFC 7517: JSON Web Key (JWK).
Some JWT libraries, like PyJWT has built in support for retrieving the keys from a JWKS endpoint, thus it's worth checking if the library you are using has support for that before implementing it yourself.
Caching
Please note that for performance reasons you should use some level of caching. The address of the jwks_uri is for example not likely to change in practice. The keys are neither rotated frequently, so they could be cached for some time, but it's still important they get refreshed once in a while.
Verifying the token signature
Once you've found the matching key (unless your library does that for you), you will need to consult the documentation of your particular JWT library on how to use it to verify the token. This varies a bit by library. In some case you might even need to convert the key to some other format accepted by the library. Covering all these possibilities is however not possible in this guide, but that information can hopefully be found from other sources using the most popular search engines.
Verifying the fields
After verifying the signature, you should do some basic verification of some of the typical fields. Many libraries by default verify the iat (Issued At) and exp (Expiration Time), but some do not automatically do it. In that case you should verify that iat <= current time <= exp. You might also want to check the iss (Issuer) matches what you expect (the consent provider of the dataspace), but this would be good to check already before fetching the keys.
Also verify the dsi field. It contains a Data Product Protocol link of the form dpp://<source>@<dataspace-domain>/<definition>, which means you will have to parse it and check it against the data source you are implementing. For example dpp://ioxio:v2@sandbox.ioxio-dataspace.com/draft/Company/Shareholders would match a data source with the group ioxio and tag v2 for the draft/Company/Shareholders definition on the sandbox.ioxio-dataspace.com dataspace. Ensure all of these match with the data source you want to provide.
You should also verify the sub (the subject from the id_token that granted the consent) and subiss (the issuer of the id_token that was used to give the consent, typically the login portal), to ensure which user actually gave the consent.
If your data source also requires authorization, you should also verify the id_token in the data source. Check the sub of both tokens match and ensure the audiss in the consent token matches the aud of the id_token and the subiss in the consent token matches the iss in the id_token.
Using the token
Once you've done all the verifications you know which user (sub+subiss) gave the consent to request the data through which application (audiss) and to which data source (dsi). Verify these match with what you want to provide and what the user has permission to request and return the requested data.