Verifier M2M Integration Guide

This guide describes how backend services and machine-operated components can integrate with the Verifier acting as an Authorization Server (AS) in machine-to-machine (M2M) scenarios. It specifies the end-to-end process required to obtain and use OAuth 2.1 access tokens based on the client_credentials grant, where client authentication relies on a Verifiable Presentation (VP) embedding a LEARCredentialMachine. The document explains the prerequisites, client onboarding and registration, secure handling of keys and credentials, construction of the VP and client assertion JWT, token acquisition via the Verifier Token Endpoint, and subsequent use of issued access tokens to call protected APIs. It also highlights security requirements, error handling, observability practices, and common pitfalls to ensure robust and interoperable integration across the ecosystem.

1. Introduction

Purpose and scope

This runbook explains how a backend service or component can integrate with the Verifier as an Authorization Server (AS) in M2M mode. It provides the end-to-end steps needed by developers: from preparing configuration and credentials, to calling the Token Endpoint with a LEARCredentialMachine, to using access tokens to consume protected APIs.

Intended audience

High‑level architecture

embedded-image-j2eCv6RV.png

  1. Client requests access token from Verifier Token Endpoint using client_credentials grant and client_assertion = VP (containing LEARCredentialMachine).

  2. Verifier authenticates client, validates VP and LEARCredentialMachine.

  3. Verifier issues access token with 1h lifetime.

  4. Client uses access token to call protected resources.

High-level flow

embedded-image-mGqKJU4g.png

  1. The client requests an access token by authenticating with the authorization server (VCVerifier) and presenting the authorization grant. Since the client authentication is used as the authorization grant, no previous authorization request is needed.

  2. The authorization server authenticates the client and validates the authorization grant, and if valid, issues an access token.

  3. The client requests the protected resource from the resource server and authenticates by presenting the access token.

  4. The resource server validates the access token presented and if valid, returns the resource requested.

2. Integration Steps

Prerequisites

Step 1 - Machine credential issuance

Outcome: machine holds a valid LEARCredentiaMachine bound to its DID.

Step 2 - Client configuration

Outcome: client is ready to authenticate.

Step 3 - Acquire token

To acquire a token, the client must build a Verifiable Presentation (VP) that contains the LEARCredentialMachine (as jwt_vc_json), sign this VP as a JWT with the machine’s private key, embed it inside a client assertion JWT with the required claims, and finally POST a client_credentials request to the Verifier Token Endpoint.

Build the VP JWT (vp_token)

LEARCredentialMachine as a JWT VC string. If it is stored Base64‑encoded, decode it first.

VP object claims:

Example VP object:

{

    "@context": ["https://www.w3.org/2018/credentials/v1"],

    "type": ["VerifiablePresentation"],

    "verifiableCredential": ["eyJhb...ssw5c"]

}

VP JWT claims (signed with the machine private key):

Example VP JWT payload:

{

    "iss": "did:key:zDna...",

    "sub": "did:key:zDna...",

    "jti": "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c5",

    "aud": "https://verifier.dome-marketplace.eu/token",

    "nbf": 1541493724,

    "iat": 1541493724,

    "exp": 1573029723,

    "vp": {

        "@context": ["https://www.w3.org/2018/credentials/v1"],

        "type": ["VerifiablePresentation"],

        "verifiableCredential": ["eyJhb...ssw5c"]

    }

}

Build the client assertion JWT

Claims (profile):

Correctness rules:

Make the request

POST /token HTTP/1.1

Host: verifier.dome-marketplace.eu

Content-Type: application/x-www-form-urlencoded


grant_type=client_credentials&

client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&

client_assertion=eyJhbGciOiJSUzI1NiIsImtpZCI6IjIyIn0...<snip>

Obtain the response

If the request is valid, the Verifier issues an access token:

{

    "access_token": "eyJraWQiOiJkaWQ6a2V5OnpEb...k9aYcDBWcGww",

    "token_type": "Bearer",

    "expires_in": 3600

}

Format of the access_token:

{

    "kid": "did:key:zDnaekiwkWcXnHaW6au3BpmfWfrtVTJZrA3EHgLvcbm6EZnup",

    "typ": "JWT",

    "alg": "ES256"

}

{

    "iss": "https://verifier.dome-marketplace.eu",

    "aud": "https://verifier.dome-marketplace.eu,

    "sub": "did:key:zDnaerQi587EqQLqEaj7qbxc46hzdjX2goNsmLTq1X6HqzzjP",

    "exp": 1745408685,

    "iat": 1745405085,

    "jti": "1700c742-5457-4c02-8e6f-020a94054519",

    "client_id": "https://verifier.dome-marketplace.eu"

    "scope": "machine learcredential",

    "vc": {

        "@context": [

              "https://www.w3.org/ns/credentials/v2",

              "https://dome-marketplace.eu/.well-known/credentials/lear_credential_machine/w3c/v2"

        ],

        "type": [

              "VerifiableCredential",

              "LEARCredentialMachine"

        ],

        "issuer": {

              "id": "did:elsi:VATES-A12345678",

              "organization": "TRUST SERVICES, S.L." ,

              "country" : "ES",

              "commonName"  : "TRUST SERVICE ELECTRONIC SEAL FOR VERIFIABLE CREDENTIALS",

              "serialNumber": "610dde5a0000000003"

        },

        "credentialSubject": {

              "mandate": {

                    "mandator": {

                       "id": "did:elsi:VATFR-B12345678",

                       "organizationIdentifier": "VATFR-B12345678",

                       "organization": "GOOD AIR, S.L.",

                       "country": "FR",

                       "commonName": "JEAN MARTIN - CNI 880692310285",

                       "serialNumber": "880692310285",

                       "email": "jean.martin@goodair.fr"

             },

             "mandatee": {

                       "id": "did:key:zDnaey7ZcQ1gfXxaZSYffjvhrrFtd7PQdQtJpofzRJNCwydHL",

                       "domain": "dpas.goodair.fr",

                       "ipAddress": "195.70.63.244"

             },

             "power": [{

                       "type": "domain", 

                       "domain": "DOME",  

                       "function": "Onboarding", 

                       "action": ["Execute"]

             }]

        }

    },

    "validFrom": "2025-09-15T06:11:19.802230162Z",

    "validUntil": "2026-09-15T06:11:19.802230162Z",

    "credentialStatus": {

         "id": "https://issuer.dome-marketplace.eu/credentials/status/1#urn:uuid:68422e47-5d69-4e0b-8a49-34990f2f76a,

         "type": "PlainListEntity",

         "statusPurpose": "revocation",

         "statusListIndex": "urn:uuid:68422e47-5d69-4e0b-8a49-34990f2f76a2",

         "statusListCredential": "https://issuer.dome-marketplace.eu/credentials/status/1"

      }

  }

}

Pitfalls to avoid