# 2. Integration Steps

### Prerequisites

- The legal entity has completed onboarding in the DOME ecosystem.
- The LEAR has obtained a valid **LEAR Credential** through the Issuer service.
- The end user (employee, contractor, etc.) has received a **Verifiable Credential** issued by the LEAR of their organization.
- DID method supported: `did:key`.
- Access to developer documentation and environment URLs (Verifier Authorization Server and APIs).

---

### Step 1 – User credential issuance

The organization’s LEAR uses the Issuer service to issue a **Verifiable Credential** to the employee or user who will log in through the public client.

- The credential is bound to the user’s DID.
- It includes roles or permissions within the organization.
- The credential is stored in the user’s **Wallet application**, which can later present it during authentication.

**Outcome:**  
User holds a valid **LEAR Credential** stored in their wallet and ready to be presented during the login process.


### Step 2 – Client configuration

**Client type:** Public (web or mobile app).

- Obtain and store the assigned `client_id,` which can be a did:key or a unique identifier.
- Register the `redirect_uri`.
- Implement [PKCE support](https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce) (`code_challenge` / `code_verifier`) to protect the authorization code exchange.
- Ensure secure handling of redirects and state parameters.

**Outcome:**  
Public client is configured and ready to initiate the OAuth 2.1 Authorization Code Flow with PKCE.

### Step 3 - Registering to the Verifier (Trusted Services List)

The relying party must be registered in the [Trusted Services List](https://github.com/DOME-Marketplace/trust-framework). The data must match with your client's configuration (see step 2).

<div align="left" dir="ltr" id="bkmrk-field-description-cl"><table><tbody><tr><td>**Field**

</td><td>**Description**

</td></tr><tr><td>clientId

</td><td>Should be a did:key or a unique identifier for your client.

</td></tr><tr><td>url

</td><td>The base URL of your service or application.

</td></tr><tr><td>redirectUris

</td><td>Must include all the URLs where you expect to receive authentication responses.

</td></tr><tr><td>scopes

</td><td>Currently, only openid\_learcredential is accepted. This scope allows your service to request the necessary credentials.

</td></tr><tr><td>clientAuthenticationMethods

</td><td>Must be set to \["none"\]

</td></tr><tr><td>authorizationGrantTypes

</td><td>Must be set to \["authorization\_code"\] and \["refresh\_token"\] if needed.

</td></tr><tr><td>postLogoutRedirectUris

</td><td>Include URLs where users should be redirected after they log out from your service.

</td></tr><tr><td>requireAuthorizationConsent

</td><td>Set to false.

</td></tr><tr><td>requireProofKey

</td><td>Set to true to force PKCE.

</td></tr><tr><td>jwkSetUrl

</td><td>Leave it blank.

</td></tr><tr><td>tokenEndpointAuthenticationSigningAlgorithm

</td><td>Must be set to ES256, as this is the only supported algorithm.

</td></tr></tbody></table>

</div>[![image.png](https://knowledgebase.dome-marketplace.eu/uploads/images/gallery/2026-03/scaled-1680-/image.png)](https://knowledgebase.dome-marketplace.eu/uploads/images/gallery/2026-03/image.png)


### Step 4 – Authorization request

The public client initiates the authentication process by redirecting the user to the Verifier’s **Authorization Endpoint**, including the required parameters:

- `client_id`: has to match the one in your client's configuration
- `redirect_uri`: has to match the one in your client's configuration
- `response_type=code`
- `scope =` `openid learcredential`
- `state` : random string
- `nonce`: random string (this will be added in the ID token, so it is recommended if you rely on the ID token)
- `code_challenge` ([derived](https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce) from `code_verifier`)
- `code_challenge_method=S256`

**Non-normative example:**

<div align="left" dir="ltr" id="bkmrk-%7B-%C2%A0-%C2%A0-%22%40context%22%3A-%5B%22"><table><colgroup><col></col></colgroup><tbody><tr><td>GET /oidc/auth?  
client\_id=did:key:zDnaeUidLS8MbNQuHsnbd3xMvfk4baLZKeWiFV7UHAv9NsmUE  
&amp;redirect\_uri=https%3A%2F%2Fapp.client.org%2F  
&amp;response\_type=code  
&amp;scope=openid%20eidas  
&amp;nonce=1234567890abcdef1234567890abcdefXYZabc  
&amp;state=1234abcd5678efgh9012ijkl3456mnop7890qrst  
&amp;code\_challenge=AbCdEfGhIjKlMnOpQrStUvWxYz1234567890abcdEfGhI  
&amp;code\_challenge\_method=S256  
Host: authserver.example.org</td></tr></tbody></table>

</div>**Outcome:**  
User is redirected to the Verifier login screen and authenticates using their Wallet and Verifiable Credential.

### Step 5 – Authorization response

After successful authentication and consent, the Authorization Server redirects the user back to the client with the authorization code and state.

**Non-normative example:**

<div align="left" dir="ltr" id="bkmrk-http%2F1.1-302-foundlo"><table><colgroup><col></col></colgroup><tbody><tr><td>HTTP/1.1 302 Found  
Location: https://app.client.org/?  
code=A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4Y5z6  
&amp;state=1234abcd5678efgh9012ijkl3456mnop7890qrst  
</td></tr></tbody></table>

</div>**Outcome:**  
The public client receives the authorization code and verifies that the returned `state` matches the one it initially sent.

### Step 6 – Token request

The client exchanges the received authorization code for tokens by calling the **Token Endpoint**.  
This request must include the original `code_verifier` used to generate the challenge.

**Non-normative example:**

<div align="left" dir="ltr" id="bkmrk-post-%2Foauth2%2Ftoken-h"><table><colgroup><col></col></colgroup><tbody><tr><td>POST /oauth2/token HTTP/1.1  
Host: authserver.example.org  
Content-Type: application/json  
Content-Length: 311

{  
 "grant\_type": "authorization\_code",  
 "client\_id": "https://app.client.com",  
 "code\_verifier": "b7f9a4b52e6347a1b8f2c3d1a6...9e0f1ABCxyz",  
 "code": "A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v2W3x4Y5z6",  
 "redirect\_uri": "https://app.client.org/"  
}

</td></tr></tbody></table>

</div>**Outcome:**  
The Verifier validates the code and code\_verifier and issues an access token and ID token.

### Step 7 – Token response

**Non-normative example:**

<div align="left" dir="ltr" id="bkmrk-http%2F1.1-200-okconte"><table><colgroup><col></col></colgroup><tbody><tr><td>HTTP/1.1 200 OK  
Content-Type: application/json  
Cache-Control: no-store

{  
 "access\_token": "eyJhbGciOiJFQ0RILUVTIiwiZ...qtAlx1oFIUpQQ",  
 "expires\_in": 3600,  
 "id\_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...p-QV30",  
 "scope": "openid profile email",  
 "token\_type": "Bearer"  
}

</td></tr></tbody></table>

</div>**Outcome:**

- `access_token` is used to call protected APIs on the Verifier.
- `id_token` identifies the authenticated user.
- Tokens have a limited lifetime (typically 1 hour).

### Step 7 – Use access token

The public client includes the access token in the `Authorization` header when calling Verifier-protected APIs:

<div align="left" dir="ltr" id="bkmrk-authorization%3A-beare"><table><colgroup><col></col></colgroup><tbody><tr><td>Authorization: Bearer eyJhbGciOiJFQ0RILUVTIiwiZ...

</td></tr></tbody></table>

</div>The Verifier validates the token, checks its signature and expiration, and grants access to the requested resources.

### Pitfalls to avoid

- Mismatch between `client_id` or `redirect_uri` in request and registration.
- Missing or incorrect `code_verifier` / `code_challenge`.
- Using a weak or predictable `state` value (CSRF risk).
- Reusing authorization codes.
- Not handling token expiration and refresh flow.
- Forgetting to set `Cache-Control: no-store` in responses.