Configuring an interaction hook 

Many credential issuance journeys require the issuer to do some custom interactions with the user. This could be gathering additional information, performing additional authentication steps (E.g, 2FA, MFA or biometric checks) or communicating terms of service.

 To facilitate this requirement, you can configure MATTR VII to invoke an interaction hook which will redirect the end user to a custom component during the credential issuance journey. This redirect happens after the user is authenticated but before the credential has been issued to the user. Upon the successful completion of this step, your custom component will redirect the end user back to MATTR VII to complete their credential issuance flow.

Your interaction hook component must be accessible by HTTPS URLs, and it could be either a web or native application.  However, we recommend using a web interface because it's more compatible to most scenarios.

Setting up the interaction hook 

This is an example to configure the interactions hook that allows the MATTR VII platform to redirect the user to your web server after completing the OpenID authentication process.

Make the following request .


Copy to clipboard.
1PUT https://YOUR_TENANT_URL/v1/openid/configuration
Copy to clipboard.
2  "interactionHook": {
3    "url": "",
4    "claims": [],
5    "disabled": false
6  }

Here’s what each field of the request payload means: 

  • url: The interaction hook URL that the user will be redirected to after completing the OpenID authentication process.  

  • claims: An array of user attributes that will be returned in the OpenID authentication response. These claims get included in the session token that is sent to the interaction hook. It is not recommended to use interaction hooks as a source of claims for the issuance of credentials. You should be using claim source as the primary source of claims.

  • disabled: A flag that indicates whether the interactions hook is disabled. In this case, it is set to false, indicating that the interactions hook is enabled. This means that users will be redirected to your interaction hook component ( after they've authenticated themselves against the IdP.


Copy to clipboard.
2  "interactionHook": {
3    "url": "",
4    "claims": [],
5    "disabled": false,
6    "secret": "dGtUrijBOT6UUJ8JO4kAFyGfhahDlVVeIk/sPbWTa7c="
7  }

You will get a shared secret as a part of the response once you finish setting up the interactions hook - as seen above.

The secret should be used by your interaction hook to sign a new JWT with any additional claims that you may include. Libraries like Jose can be used for node servers.


Your interactions hook server/component is responsible for verifying your users, and it is exposed to the public internet, which means you must apply access controls to protect it from unauthorised access.

MATTR VII interactions hook integration supports a JWT (HS256)-based authorisation scheme to help enable this.  

Get the shared secret 

To sign the JWT, we need to use the secret that is returned when you update your interaction hook.   

Your interaction hook component will use this secret to verify the JWT token that MATTR VII sends back.

Verify the session token  

 When MATTR VII redirects the end user to your interactions hook component, it will also include a JWT as a session_token query parameter.  

Copy to clipboard.

This JWT contains key information such as redirectUrl, which is used to redirect users back to the mobile wallet after they completed verification processes on the interaction hook component.

You should verify the JWT against the shared secret to make sure that the request is legitimate.

Here is an example code snippet using the panva/jose library to verify the JWT:

Copy to clipboard.
1import { jwtVerify } from "jose";
3// Retrieved from URL session_token query parameter
4const jwt = "YOUR_JWT";
6// Recieved when you created an interaction hook on your tenant
7const secret = Buffer.from("SHARED_SECRET", "base64");
9const issuer = "https://YOUR_TENANT_URL";
11// The URL of your interation hook
12const audience = "";
14const verifiedJwt = jwtVerify(
15  token,
16  secret,
17  { issuer, audience }

 The JWT is stored as a string in the jwt variable.  

The secret variable contains the secret key that will be used to verify the JWT signature.

The issuer and audience variables are used to define the expected issuer and audience values for the JWT. 

If the verification is successful, the function will return the decoded payload of the JWT. If the verification fails, an error will be thrown. 

Extract the session token payload  

After verifying the session token, your interactions hook component can extract several values from the decoded JWT payload. 

Here is an example decoded payload with values that can be extracted:  

Copy to clipboard.
2"state": "hJvfiSp3eEGybd-KmL8ja",  
3"scopes": ["ldp_vc:CourseCredential"],  
4"claims": { "email": "" },  
5"authenticationProvider": {  
6      "url": "",  
7      "subjectId": "user|123456789"  
8   },  
9"redirectUrl": "https://YOUR_TENANT_URL/core/v1/oauth/interaction/hJvfiSp3eEGybd-KmL8ja/interactionhook/callback",  
10"sub": "a44a7f92-c61e-48a0-88b6-863eeeb58394",  
11"aud": "",  
12"iss": "",  
13"iat": 1673910963,  
14"exp": 1673911263  

Here's what each of the values represents:

  • state: A unique value associated with each interactions hook session

  • scopes: Scopes from end-user authorisation request  

  • claims: User claims from Interactions Hook configuration

  • authenticationProvider: A provider that the user is authenticated with 

    • url: URL of the authentication provider 

    • subjectId: Subject Identifier of the end user for this provider 

  • redirectUrl: Url to redirect to when users complete interacting with the interactions hook component

  • sub: Subject identifier of the end user for MATTR VII  

  • aud: Your interactions hook component 

  • iss: Your MATTR VII tenant 

  • iat: Issued at (seconds since epoch)

  • exp: Expiry (seconds since epoch) 

Response from interactions hook component  

Once the end user has completed the custom journey, they need to be redirected back to MATTR VII to complete the credential issuance.  The redirect URL can be found in the session token sent from MATTR VII to the interactions hook component above.  

Additionally, the issuer must generate a new JWT session token and include it as a query parameter. This responding session token can be used to sync new claims with MATTR VII and used during issuance.  


Copy to clipboard.

Generate a session token with claims  

Your interactions hook component needs to sign the session token that is part of the redirect URL. This token can contain claims for the user as well.

To generate the session token with claims, use:

  • The same shared secret described in the authorisation section above.  

  • The state value from the session token payload described in the authorisation section above.  

Optionally, include new or updated claims you wish to merge with the existing end user claims on MATTR VII. These claims will be available for use during issuance.  

Copy to clipboard.
1import { SignJWT } from "jose"; 
3const secret = Buffer.from(
5  "base64"
8const jwt = await new SignJWT({ 
9    state: "hJvfiSp3eEGybd", 
10    claims: { myNewClaim: "foobar" } 
11  })
12  .setProtectedHeader({ alg: "HS256", typ: "JWT" })  
13    .setIssuedAt()
14    .setExpirationTime("1m")  
15    .sign(secret);  

The setProtectedHeader method is used to set the protected header of the JWT. In this case, the protected header includes the alg algorithm (set to "HS256") and the type token type (set to "JWT"). 

The setIssuedAt method is used to set the "issued at" (iat) claim to the current time. This indicates when the JWT was issued. 

The setExpirationTime method is used to set the expiration time (exp) claim of the JWT. In this case, it is set to expire 1 minute after it is issued. 

The resulting signed session token (JWT) will be used to transmit claims securely between systems. 

Handling Errors

If your interaction hook determines that the user should not be allowed to continue with the issuance journey, you can return an error message in your signed JWT which will signal to the issuance journey that it should fail.

Here is an example of how to structure an error JWT:

Copy to clipboard.
1import { SignJWT } from "jose";
3const jwt = await new SignJWT({
4  state: "hJvfiSp3eEGybd-KmL8ja", 
5  error: {
6    message: "Insufficient identity assurance level"
7  }