Skip to main content

Integration Steps

Prerequisites


Step 1 – Generating key pair: did:key + private key

You will need a did:key / private-key pair. It can be obtained through different methods. One option we can propose is to use our Issuer: when issuing a LEARCredentialMachine, a key pair is generated for the client. The corresponding did:key is set as the mandatee.id in the credential (which you can check in the details page after issuing it --no need to activate it). The private key must be kept securely on your side and is never shared.


Step 2 – Client configuration

Client type: Confidential.

  • Obtain and store the assigned client_id, which should be the did:key generated in the previous step.
  • Ensure the redirect_uri is pre-registered and uses HTTPS.

  • Implement JWT-based client authentication (client_secret_jwt). You client will need a request_uri where a signed JWT token must be exposed (see the authorization request step).

Outcome:
The confidential client is fully configured to authenticate using signed JWTs and perform the Authorization Code Flow.

Step 3 – Registering to the Verifier (Trusted Services List)

The relying party must be registered in the Trusted Services List. The data must match with your client's configuration (see step 2).

Field

Description

clientId

Should be a did:key that identifies your client.

url

The base URL of your service or application.

redirectUris

Must include all the URLs where you expect to receive authentication responses.

scopes

Currently, only openid_learcredential is accepted. This scope allows your service to request the necessary credentials.

clientAuthenticationMethods

Must be set to ["client_secret_jwt"]

authorizationGrantTypes

Must be set to ["authorization_code"] and ["refresh_token"] if needed.

postLogoutRedirectUris

Include URLs where users should be redirected after they log out from your service.

requireAuthorizationConsent

Set to false.

requireProofKey

Set to false.

jwkSetUrl

Since you're using a did:key for your clientId, you do not need to provide your own jwkSetUrl: the verifier can derive your JWKS directly from the did:key. Just add this string: “<verifier-url>/oidc/did/<your-did-key>”. 

tokenEndpointAuthenticationSigningAlgorithm

Must be set to ES256, as this is the only supported algorithm.

image.png


Step 4 – Authorization request

The confidential client starts the authorization process by redirecting the user to the Authorization Endpoint with these 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)

  • request_uri: see the explanation below*

Non-normative example:

GET /authorize?

response_type=code

&client_id=did:key:wejkdew87fwhef9833f4

&request_uri=https%3A%2F%2Fapp.client.com%2Frequest.jwt%2F3Gr...AdM

&state=af0ifjsldkj

&nonce=n-0S6_WzA2Mj

&scope=openid%20learcredential

Host: authserver.example.org

*The request_uri. must expose an  Authorization Request Object., which is an JWT and must include these parameters. These parameters must match the ones of your client's configuration (and the ones included in the request as well):

  • client_id
  • scope
  •  redirect_uri

 The Authorization Server retrieves this JWT, validates its signature against the client’s registered jwkSetUrl(that is, against the public key derived from you did:key), and proceeds with the flow.


Outcome:
The Authorization Server successfully validates the signed request and displays the login and consent screen to the user.

Step 5 – Authorization response

After the user successfully authenticates and authorizes access, the Authorization Server redirects back to the client’s redirect_uri with an authorization code.

Non-normative example:

HTTP/1.1 302 FOUND

Location: https://app.client.com/cb?

code=SplxlOBeZQQYbYS6WxSbIA

&state=af0ifjsldkj

Outcome:
The confidential client receives the authorization code and verifies that the state matches its original request to prevent CSRF attacks.

Step 6 – Token request

The client exchanges the authorization code for tokens by calling the Token Endpoint.
In this step, the client authenticates using client_secret_jwt, sending a signed JWT in the client_assertion parameter.

Non-normative example:

Non-normative example of a Token Request:

POST /oauth/token HTTP/1.1

Host: authserver.example.com 

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


grant_type=authorization_code

&code=SplxlOBeZQQYbYS6WxSbIA

&redirect_uri=https%3A%2F%2Fapp.client.com%2Fcb

&state=af0ifjsldkj

&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=eyJhbGciOiJFUzI1N...


Outcome:
The Authorization Server validates:

  • The client_assertion signature.

  • The authorization code and redirect URI.
    If valid, it issues access, ID, and refresh tokens.


Step 7 – Token response

Non-normative example:

HTTP/1.1 200 OK

Content-Type: application/json

Cache-Control: no-store

Pragma: no-cache


{

  "access_token": "eyJhbGciOiJFQ0RILUVTIiwiZ...qtAlx1oFIUpQQ",

  "token_type": "Bearer",

  "expires_in": 3600,

  "refresh_token": "8xLOxBtZp8",

  "id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...p-QV30"

}


Outcome:

  • access_token grants access to protected APIs.

  • id_token identifies the authenticated subject.

  • refresh_token allows new tokens to be obtained without user interaction.

Step 8 – Use access token

The confidential client uses the access_token to call Verifier-protected APIs:

Authorization: Bearer eyJhbGciOiJFQ0RILUVTIiwiZ...