Skip to main content

Encrypted/signed responses from Signicat

As per OIDC specification, Signicat can send encrypted responses. This means we always encrypt the ID tokens and UserInfo responses for a given OIDC client.

Responses from Signicat are fully encrypted on the transport layer with HTTPS, but adding message-level encryption can be used as an additional security layer.

This section explains how to set up and process encrypted responses.

Finnish Trust Network (FTN)

For FTN you are required to receive encrypted responses. In fact, FTN fails if you do not set this up correctly and you are not able to obtain any FTN authentication results.

Prerequisites

Typically you don't need to create your own keys, as you can generate key pairs in the Signicat Dashboard. If you do want to fully manage your own keys, you need to first generate one and then import it and store it in the Signicat Dashboard, from where we can fetch it.

If you wish to create your own key pair, these are the technical requirements:

  1. Generate a JWK RSA key pair (2048-bit) suitable for encryption. We also support 4096-bit if required. It is important that you create a JWK or an X509 certificate. We recommend using the JWK format.
  2. Store the public part of your key pair in a text file (typically .json).
Bringing you own key pair

If you choose to create your own key pair, then in the next section select Import public key instead of Add public key.

Required configuration

  1. In the Signicat Dashboard, go to Products > eID Hub > OIDC clients.
  2. Select your OIDC client. To create a new OIDC client, see Set up an OIDC client.
  3. In the client menu, go to Advanced > Public keys and select Add public key. Instead, select Import public key if you want to import your own key.
  4. Fill in the Name, Not valid before and Not valid after fields for your key.
  5. Select Encryption as the Usage.
  6. Now, select Create.
  7. A key pair is generated for you. This contains a public key and a private key. Take a copy of the private key and store it somewhere safe.

You now have an encryption key that we can use to encrypt the responses we send to you, and that you should be able to decrypt.

Finally, you need to configure the encryption on your client:

  1. In the Signicat Dashboard, go to Products > eID Hub > OIDC clients. Then, select again your OIDC client.
  2. In the menu for the client, select Advanced > Security.
  3. Under User Info Response Type select SignedAndEncrypted. (If you prefer you can also select Encrypted, which is out of scope for this guide.)
  4. Enable Encrypt ID Tokens.

You are now ready to continue to the implementation.

Implementation

You should send your requests as normal OIDC requests, since what changes are the responses you receive from Signicat. The ID token and the response from UserInfo is a nested JWT which is encrypted and signed. To process it:

  1. Decrypt it with your private key from the key pair provided in the Signicat Dashboard.
  2. Deserialise the resulting signed JWT and verify it, as you would do with a normal token.

Code example

Important

This code example is for illustrative purposes only. It is not intended for production usage. Signicat takes no responsibility if this code example is used inappropriately.

from jwcrypto import jwk, jwe

# ATTENTION: Insert your nested JWT (that you got from Signicat OIDC server) here!!!
jwe_serialized = "eyJh...QifQ.Qq5TQR...xN-PQ.ojSGehTV7xw_xE078sFnTg.in8a...SITqA.SyVNrXe0C3UkKBQ_AVyQiw"

# For the sake of simplicity, the JWKs has been manually loaded into a dictionary.
# In a real life scenario you should do this in a secure manner: The jwe_private_key should be stored securely on your premise.
jwe_private_key = {
"alg": "RSA-OAEP",
"d": "MODJkQVnKx-txB11QSkz2roacDL9z-BqcDq-dYM2OHrI-x4iNpdBWtoS2Hi4OfH6ETmzMnFNVY3oIYoaMTuuWKc0r_QeIIqbkt8MozALusETiB2VtiAiiZU6G2DyAOFaWaoiIlRYO5BciDCM6z4ytfnDFYM7-K-YSA3_V7jDSGjRroGC112lVs9BzA3qjCP8jnb9VvNKUhdcFqsqGU8eRw8fZp73uHyEm9tVHimSPjyLda3XlcxPSEkhqlP4aaleWhkUQJM3bc2YDnpWBjlNuIHsacEA28xrwOqHSqK-b8klvxk-e_w-C-SdlcYhgB5DeSB0bEuCpmV9GKwOp0KhuQ",
"dp": "hkPXP00qlIrioShp3FiXp0_OahJXe4cVNAXLJYgKRsqv72I7AXZltAOXNRanpQDQutDADFsMTx1XxoEQm_GUvTUe-dS-PkBGKJMLjp28zs9G0L4yXUXenKu_vs-3wD4_06WtT_kOyJD48LaQno6SYdUm4JBvS5A1ve2NYI7xDEk",
"dq": "WGmNHsCzREbHgwQCStW9munP16NJzdeXJ0ys7QbLwpOxMEP1BkSznoRw4_0IkSxTtyvWPG9Eo-bPCKfkqILUowG7tniIerf0F6LkCjssPk5wNxEK_Ktt-59_3Wrvs9Iik4tYF0bEqlXyidFq7ayBoRdiPZ0-ELjU-hEqY0GR0Ok",
"e": "AQAB",
"kid": "mykey-123",
"kty": "RSA",
"n": "zOeJ1RJOgP6NlgwEcqa-BtHUC5nNNa2UbsQQsNDQa6KioVcNfiz5WWmQF3FAR7HTAxQveXfgT7PqOmPgiDVHTLcdYlOjcOAESCTFYELsuh58xnA99agM9vPuLVo2x-hwjE_b-1dC3Ph2_gpXwqS6JDjKa5VF-5zMLbVLQJ96yhKGqzQ7TrfXrEcgfzXMipTbQTxpDAFnTyYYQ7lOVp_ms0Kbz4fpRbyGUtzYsgkYBCNwfWgtfXZW7ahMeb84ukbH2nXXQKQsxuSYU-gbK44yVvcvltqg5wMjG39Xo-BUGlJGQzEN0-6QEIqGrMXgTx5B147IV22vT7demmNx2_RXDQ",
"p": "-3lVxpmyecuu7-tceX7eoVjHmUlbHzUkhehkV_axQx5FtX5NRWdzqg8jhmPBBRpMtvG7g55ZQihVTi3sphfP0k1czEPsgJt8diZ4KIMDgimcksyJ8yPP0dZuvdnBVFVdlJDWfimmLxmFwlmw-p3gCAPePbqRjD1vo25Bwi5Dujk",
"q": "0JeicVX3YgVhUXuY_f3BX-VDKR0LH_SLaIaEimuvpleo5AM4El_An8SR-_Z1GXZuzsOvff7d_E79NjwsdhtKKxQiW93awsFD9Fd5fqNUOpB0ikAf-gNz6MCujt9nhS_jvbMsNI6gCRexZ4gD-RB9dj_qXsWWJUJQpcu7QMmeE3U",
"qi": "-MNE31_wnD2aRLiZz0piLD6lHJwSYpGFinBKWp5VPuLdeXAruSdKW82oRTapA-y6s87fB85jcjvW3dAYjzFFsFNpjDzrpCwctIsQVzZt_vVu5Mdon365tFHWyH2xAcTmVxdJGDunR6BKMmnciCdXTgZP8wSAEWrjmVop_ontfM8",
"use": "enc"
}
# Loading JWK key
jwk_jwe_private_key = jwk.JWK()
jwk_jwe_private_key.import_key(**jwe_private_key)

jwetoken = jwe.JWE()
jwetoken.deserialize(jwe_serialized)
jwetoken.decrypt(jwk_jwe_private_key)
jws_serialized = jwetoken.payload
print("\nSIGNED JWT (just like a normal ID token):\n")
print(jwetoken.payload)