Trusted Identity

Trusted Identity

Trusted Identity is a signed JWS token (in JWT format) that the Partner/Tenant backend passes to the Verestro backend to authenticate the request and initiate an end-user session. The token is verified cryptographically (signature + certificate chain in x5c) and organizationally (verification of CN according to the onboarding configuration).


1) Purpose and Use

What it is

Why it is used

Token Issuance and Verification – sample usage

@startuml skinparam ParticipantPadding 30 skinparam BoxPadding 30 skinparam noteFontColor #FFFFFF skinparam noteBackgroundColor #1C1E3F skinparam noteBorderColor #1C1E3F skinparam noteBorderThickness 1 skinparam sequence { ArrowColor #1C1E3F ArrowFontColor #1C1E3F ActorBorderColor #1C1E3F ActorBackgroundColor #FFFFFF ActorFontStyle bold ParticipantBorderColor #1C1E3F ParticipantBackgroundColor #1C1E3F ParticipantFontColor #FFFFFF ParticipantFontStyle bold LifeLineBackgroundColor #1C1E3F LifeLineBorderColor #1C1E3F } actor User participant "Partner/Tenant (Backend)" as A participant "Verestro (API)" as B User -> A: Session start request A -> A: Build payload (userId, iat, jti) A -> A: Add x5c (leaf + intermediates) A -> A: Sign JWS (RS256, private key) A -> B: Send Trusted Identity (JWS) B -> B: Read Root CA + expected CN B -> B: Validate x5c chain to Root CA B -> B: Validate CN/DN === expected B -> B: Verify JWS signature B -> B: Check iat TTL (10 min) B -> B: Start user session for userId B --> User: Session active @enduml

2) Integration / Onboarding

Variant A (recommended): Partner/Tenant provides CSR

The Partner/Tenant:

Verestro:

The Partner/Tenant:

Variant B: Partner/Tenant provides Root CA

The Partner/Tenant provides:

Verestro:

Onboarding variants

@startuml skinparam ParticipantPadding 30 skinparam BoxPadding 30 skinparam noteFontColor #FFFFFF skinparam noteBackgroundColor #1C1E3F skinparam noteBorderColor #1C1E3F skinparam noteBorderThickness 1 skinparam sequence { ArrowColor #1C1E3F ArrowFontColor #1C1E3F ActorBorderColor #1C1E3F ActorBackgroundColor #FFFFFF ActorFontStyle bold ParticipantBorderColor #1C1E3F ParticipantBackgroundColor #1C1E3F ParticipantFontColor #FFFFFF ParticipantFontStyle bold LifeLineBackgroundColor #1C1E3F LifeLineBorderColor #1C1E3F } participant "Partner/Tenant" as C participant "Verestro" as P alt Variant A (recommended): CSR signed by our CA C -> C: Generate RSA keypair C -> P: Send CSR (CN=uniquePartner/TenantName) P -> P: Sign CSR with our CA P -> C: Return certificate (+ intermediates if any) P -> P: Configure our Root CA + expected CN/DN else Variant B: Partner/Tenant provides Root CA C -> P: Provide Root CA + expected CN/DN P -> P: Configure Root CA + expected CN/DN end @enduml


3) Structure

The token has the following format: {base64url(header)}.{base64url(payload)}.{base64url(signature)}

3.1 Header

Required fields:

Example:

{
  "alg": "RS256",
  "typ": "JWT",
  "x5c": [
    "MIIC... (leaf)",
    "MIID... (intermediate)"
  ]
}

3.2 Payload (claims)

Required fields:

Example:

{
  "userId": "external-987654",
  "iat": 1739191200,
  "jti": "a3f1c3d6-0d3b-4f2e-9c24-8d6b9b2a9f0d"
}

3.3 Signature


4) Security Requirements (TTL)

TTL (token validity)


5) Trust Based on x5c and CN/DN Validation

What Verestro verifies

  1. Construction and validation of the certificate chain from x5c up to the configured Root CA.
  2. Validation of the certificate's CN against the value established during the onboarding process.
  3. JWS signature verification using the public key from the leaf certificate.
  4. Validation of iat (TTL) and jti (replay protection), and presence of userId.

CN rule (integration requirement)


7. Examples and Test Methods – those should be used for development and testing purposes only.

7.1 Trusted Identity example:

Token generated with the following payload will look like this:

{
  "iat": "1770981506093",
  "jti": "1b290b62-8e1e-4168-bb24-5c29d22ee699",
  "userId": "some-external-user-id-1234"
}

"eyJhbGciOiJSUzI1NiIsIng1YyI6WyJNSUlGeFRDQ0E2MmdBd0lCQWdJVWNMWmtmN0EyZFdvNHdKT1NlVEdpbnMvdlVQTXdEUVlKS29aSWh2Y05BUUVMQlFBd2NqRUxNQWtHQTFVRUJoTUNVRXd4RkRBU0JnTlZCQWdNQzAxaGVtOTNhV1ZqYTJsbE1ROHdEUVlEVlFRSERBWlhZWEp6WVhjeEZEQVNCZ05WQkFvTUMxWmxjbVZ6ZEhKdklGTkJNUXd3Q2dZRFZRUUxEQU5FUlZZeEdEQVdCZ05WQkFNTUQxWmxjbVZ6ZEhKdlgwTkJYMFJsZGpBZUZ3MHlNVEF5TURnd056TTVOVEZhRncweU5qQXlNRGN3TnpNNU5URmFNSEl4Q3pBSkJnTlZCQVlUQWxCTU1SUXdFZ1lEVlFRSURBdE5ZWHB2ZDJsbFkydHBaVEVQTUEwR0ExVUVCd3dHVjJGeWMyRjNNUlF3RWdZRFZRUUtEQXRXWlhKbGMzUnlieUJUUVRFTU1Bb0dBMVVFQ3d3RFJFVldNUmd3RmdZRFZRUUREQTlXWlhKbGMzUnliMTlEUVY5RVpYWXdnZ0lpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElDRHdBd2dnSUtBb0lDQVFEbkZIZzB4Q0prckYwNFVSc0p0em5aVndxOWxrVUd2Z3J3K2RVVzh5aS9MV0VoMC9QU2hLVmUxNEFqWktXSXJaU3FRNDR6d0Mwbk04c0NyRjgvWnJxVFYvc0Q3dTQ5WnMzeko2TkVOQk83VTI0blZpeUxiaDNQQkZReEcyYWd6Q0ZTUXpEMTdpR0ZxckxYa29vQWVOMVllczRUc0FSdzlzK21aMlhydzlEaGdVa3pFZUZwcXo1c3J2N3huMFpLdjh4czMrZjd1SUlGdWdSWFhYVWltUmdCWXQ3dzk0SmgxblRpQis0SU1RSXBFR2Vmd29HTmlKL0IvWThsVXJVLzd1TnhKTHc2UU54dG52ZkFNaVJReGV4ektPc21RMWVxd1MrWWlQTVc3MG8vOVJHMmRRaWZyYWRpOU9JRjlqZmUxbzhxSVRQUG1nRG9aVWI1dWYrSGFybXdrSEs1SjBUcWpkZWZaNjlwYTVwWUppQzNsOUNOYlh1YzI3VVhuZmQxK2dwckdZMjdhMjgyemMwQnZad1FjL085blZIclVBeVh4OGR3MjIwK3RkUDZzSkFKMUV6YUpaVWltcDBka0hENkhLbmp3WjJ1L2RtMi83RzFYSnpiY0IzSStDMWlmbXdEYXhoWlVUbGpweGRBbklpbFU5WUpmOU14UVUwRGJ6bGVxMS9Sc01DWU9rSUpoZjVwZXdPMXFmSVlLK0V2a05iRzI5VzRqdGtNOFNISTdVRUFNN3hrWk1qVkNaamNMZnBzUk5LMWNjTnpFTEF3V2lHWG8yaVhEVmdBUStVUVU2cHBQdFQyb0ZVWWU3aWpFSit0RnEzQWd3UzIvMldnL1RvOVlhbitWM2luN2IxUURmTlJVc1BxeDgrTFlLcHhCRGVhMjBlR3FBZ1VTYzNEVFFJREFRQUJvMU13VVRBZEJnTlZIUTRFRmdRVWlteVhrSDE4bGhzRXc1ai9UaldCZ0d2NDNhSXdId1lEVlIwakJCZ3dGb0FVaW15WGtIMThsaHNFdzVqL1RqV0JnR3Y0M2FJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQWdFQVhlM0ZGMm1zRC9qdllyYW03SnBpQlUvbFB0dEx0bmdpL3pCTGM4Y0dKbGlhcTM2S1h1ZWdpRWp3cjJtT1ExeXNaUXRQSnUrZjg4TXBPWU9QdDFBZm1QN1RRZ0ZZTjRyOFJVU2RxOEMwVTlUOFZvNUJxaXh4WFl6Z0xBSi8wTkZpZmx3YVJLN2FKOUdza1MrNkFoRUppRTdyNkl1cTZScWVyS3VvYkZvaEtQdHZLZkM5ZjBvcEwxVDBlV296L3BVNTBOTDM5QXpETkk5Tkh5MWdPQnNGNElYSHRUeHN1eTJCNjVyTkpjSjdKbmNkc0xhdWVhL3doa1hoUWRkUTVrN25MbUJ4eFl2M0RWZmNkZ2dYUXF0S3ZKQnh4SE9Gak1yUzdDYXVud2h6WDlJQW05Ny82MU8zNXVkd1dKVHZ0eFJnNEFWTGNOWXhjRHZTNlN3WVhud0dQak5BS0QvNXdpcStTMlZib1Z4UkJqSm12cEVhRU5WQ3djQnlvZ3ZidnlXcEd6WkhOUGdDRmVUVFRIYU51ZWJxL05XYmJ4QWM2bWhxM3d5bC9mYnBwakRhTno1U2hlbVFCdVVhbVZ1WlBZNVJDS2FUc2twSElTT0UyT1RrMkEzVkpuajA1cm0wQUY1QWlRbjJjWThJM3dYODlseFZRc3YrRjQyR2VMalVRMnVqMDR5dEliSjNnYUlBVFE3ODMvRjVuRkFVY0o0VWNGcXRFRXZEYVVkMEkrbFRtZkQzTEc0Y3E2STRheUd2Z04zS2NURW1PUU43ZlZPNWlvRjJFSk5oK1dRTHNuQ1RaTkgxc2dOSk53ajRRSlduSzVaYThPcTNzZk9jRDVraVE0ZmoxbW9HNmhRWkxQM3J6OVZZR2lCWTF2aWlGVG5RcWhJYjlOdzlrQ1NDaWEwPSJdfQ.eyJpYXQiOiIxNzcwOTgxNTA2MDkzIiwianRpIjoiMWIyOTBiNjItOGUxZS00MTY4LWJiMjQtNWMyOWQyMmVlNjk5IiwidXNlcklkIjoic29tZS1leHRlcm5hbC11c2VyLWlkLTEyMzQifQ.m75hzT1Wn4RW4wxVLdNm5wukVMtT-5J6h8PldaHfQ19WGqlx2x4wa5Ut2xKORaoMZOOkGMP1VKbOa-_MgFWeSR6nwyiUXoa7zDh7MNnUD7C1yCk-eVQDdSoFIQIg7UBjVj0uJZYkUOmScz0MjCpeZ-hhFVQInnHK-8YNdR1A5L-S5-d57pubz0C2GarIJu7z1d-qytfQFGdqvMAMuu9cPwc4oIfB4VajYqsz_NWWqSrsBNGnZIhuVKsWs1KXki3B2Z1v55tbET61bvZzuc7lEK27HzYaELC_za4zK0OP0GlqEl0gYzbj60E2sEE23jlUbiGj1Craq4KRrGpBAMDsgX0_kOicfQDjeYJ2wIouU2svDxLtI_BBiz7yT-opRTu0A-uDworfyWyt5IaZi9ZGOc_4--gwTWvrv1Bp9BPLZ8t6huSeJ4pjQTWMAZ_T2s2m69HWIIkIp0xDgkWBWlByEh-3ptzY_X3tZGtt7wjRH8AJrSeOXKPCDn9nZKu_sfaNFaDJGb28FajHR7u5xXUgif4DK9yFisaZf_SaXCkcO1KYO0oZD5Vy0gX-ZNJSVGX0yKm7wxHXBG1JPmHrvL-ieztM0PLBSR38I5CUJCHNLBlL2Cbw8YBuo-ubU0JxpgZ0i1g25Rxv1wVgYuw8x5ckxNpTjgsm08m-m-WcDxEAk_s"

7.2 Test methods

curl --location 'https://datacore.verestro.dev/test/generate-jws-x5c-token' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Issuer-Code: YOUR_TENANT_ID' \
--header 'Application-Id: YOUR_TENANT_APP_ID' \
--header 'Authorization: Basic dGVzdDE6dGVzdDEyMw==' \
--header 'Collection: internal' \
--data '{
    "iat": "1770981506093",
    "jti": "1b290b62-8e1e-4168-bb24-5c29d22ee699",
    "userId": "some-external-user-id-1234"
}'
curl --location 'https://datacore.verestro.dev/test/read-jws-x5c-token' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Issuer-Code: YOUR_TENANT_ID' \
--header 'Application-Id: YOUR_TENANT_APP_ID' \
--header 'Authorization: Basic dGVzdDE6dGVzdDEyMw==' \
--header 'Collection: internal' \
--data '{
    "token": "eyJhbGciOiJSUzI1NiIsIng1YyI6WyJNSUlGeF..................0qYz-H_0LEK0M"
}'

Output:

{
  "verified": true,
  "token": {
    "iat": "1770981506093",
    "jti": "1b290b62-8e1e-4168-bb24-5c29d22ee699",
    "userId": "some-external-user-id-1234"
  }
}