GuidesOID4VCIInteraction hook

How to create and use an Interaction hook

As part of an OpenID4VCI issuance workflow, you can invoke an Interaction hook which will redirect the user to a custom component as part of the workflow. This redirect happens after the user is authenticated with your configured Authentication provider but before the credential is issued to the user. Upon successful completion of the interaction hook component, the user is redirected back to their digital wallet to complete the OID4VCI workflow.

You can also configure your Interaction hook via the MATTR Self Service Portal.

Prerequisites

  • Web or native application the interaction hook will redirect the user to.

Overview

Creating and using an Interaction hook as part of an OID4VCI workflow comprises the following steps:

  1. Configure a MATTR VII Interaction hook.
  2. Verify the Interaction hook redirect JWT.
  3. Use the decoded payload.
  4. Sign the Interaction hook response JWT.
  5. Handling errors

Configure a MATTR VII Interaction hook

Request

Make a request of the following structure to configure an Interaction hook:

HTTP
PUT /v1/openid/configuration

Request body

JSON
{
    "interactionHook": {
        "url": "https://example-webapp.com/callback",
        "claims": [],
        "sessionTimeoutInSec": 1200,
        "disabled": false
    }
}
  • url : The interaction hook URL that the user will be redirected to after completing the authentication process:
    • Must be a valid URL.
    • Must use the HTTPS protocol.
    • Must not be an IP address.
    • Must not include query parameters.
  • claims : An array of user attributes that are available from the Authentication provider response. These claims are included in the session token that is sent to the interaction hook.
  • sessionTimeoutInSec : Interaction hook session duration (in seconds). Once a session expires, the user is shown an error when they are redirected. If not specified, the default environment session duration is applied.
  • disabled : Indicates whether the Interaction hook is disabled. When false, the Interactions hook is enabled and users are be redirected to your interaction hook component (http://example-webapp.com/callback) after they’ve authenticated with your Authentication provider.

Response

JSON
{
    "interactionHook": {
        "url": "https://example-webapp.com/callback",
        "claims": [],
        "sessionTimeoutInSec": 1200,
        "disabled": false,
        "secret": "dGtUrijBOT6UUJ8JO4kAFyGfhahDlVVeIk/sPbWTa7c="
    }
}

Verify the Interaction hook redirect JWT

Once the Interaction hook is configured, MATTR VII will redirects users following their authentication with the configured Authentication provider to the configured interaction hook component. This redirect includes a JWT object as a session_token query parameter, as shown in the following example:

HTTP
https://example-webapp.com?session_token=REDIRECT_JWT

To ensure that the redirect is legitimate, your interaction hook component must verify the JWT object using the interaction hook secret (obtained from the response above).

You can achieve this for node servers using libraries like Jose, as shown in the following example:

TypeScript
import { jwtVerify } from 'jose'
 
// Retrieved from URL session_token query parameter
const jwt = 'YOUR_JWT'
 
// Retrieved when you configured the interaction hook on your tenant
const secret = Buffer.from('SHARED_SECRET', 'base64')
 
// This is your tenant's URL
const issuer = 'https://{learn.vii.au01.mattr.global}'
 
// This is your interaction hook component URL
const audience = 'https://example-webapp.com'
 
const verifiedJwt = jwtVerify(jwt, secret, { issuer, audience })
  • The following variables are defined:
    • The jwt variable stores the redirect JWT.
    • The secret variable stores the secret returned when you configured your interaction hook.
    • The issuer variable stores the URL the redirect is coming from (this should be your tenant’s URL).
    • The audience variable stores your interaction hook component URL.
  • The jwtVerify function then uses these variables to verify the redirect JWT:
    • If the verification is successful, the function will return the decoded JWT payload.
    • If the verification fails, it means the JWT payload should not be used and an error is thrown.

Use the decoded payload

Here is an example of a verified and decoded JWT payload with values that can be extracted and used by your interaction hook component:

JSON
{
    "state": "hJvfiSp3eEGybd-KmL8ja",
    "scopes": ["ldp_vc:CourseCredential"],
    "claims": {
        "email": "learn@mattr.global"
    },
    "authenticationProvider": {
        "url": "https://myidentityprovider.auth0.com",
        "subjectId": "user|123456789"
    },
    "redirectUrl": "https://learn.vii.au01.mattr.global/v1/oauth/interaction/hJvfiSp3eEGybd-KmL8ja/interactionhook/callback",
    "sub": "a44a7f92-c61e-48a0-88b6-863eeeb58394",
    "aud": "https://example-webapp.com",
    "iss": "https://learn.vii.au01.mattr.global",
    "iat": 1673910963,
    "exp": 1673911263
}
  • state : A unique value associated with each Interaction hook session.
  • scopes : Scopes retrieved from user authentication workflow.
  • claims : User claims defined when you configured your interaction hook.
  • authenticationProvider : A provider that the user has authenticated with.
    • url : URL of the Authentication provider.
    • subjectId : Subject Identifier of the end user with this Authentication provider.
  • redirectUrl : Url to redirect to when users complete the Interaction hook journey.
  • sub : MATTR VII end user subject identifier.
  • aud : Interaction hook URL.
  • iss : Your MATTR VII tenant.
  • iat : Issued at (Epoch Unix timestamp)
  • exp : Expires at (Epoch Unix timestamp).

Sign the Interaction hook response JWT

Once the user completes the interaction hook component journey, they must be redirected back to MATTR VII to complete the OID4VCI workflow. The redirect URL can be found in the decoded JWT payload above.

For MATTR VII to ensure this redirect is legitimate, your interaction hook component must generate and sign a new JWT token and include it as a query parameter with the redirect.

Signing the response JWT

Here is an example of using the same Jose library to sign a new JWT session token:

TypeScript
import { SignJWT } from 'jose'
 
const secret = Buffer.from('<SHARED_SECRET>', 'base64')
 
const jwt = await new SignJWT({
    state: 'hJvfiSp3eEGybd-KmL8ja',
    claims: { myNewClaim: 'foobar' },
    claimsToPersist: []
})
    .setIssuer('https://example-webapp.com')
    .setAudience('https://learn.vii.au01.mattr.global')
    .setProtectedHeader({ alg: 'HS256', typ: 'JWT' })
    .setIssuedAt()
    .setExpirationTime('1m')
    .sign(secret)
  • secret : Same value used for verifying the interaction hook redirect JWT.
  • state : Unique value associated with each interaction hook session, available in the decoded redirect JWT.
  • claims : Claims gathered during the interaction hook journey that you want to pass back into MATTR VII. These claims will be available during issuance and will not be persisted on your tenant unless configured to do so using the claimsToPersist field.
  • claimsToPersist : Indicates transferred claims that you want to persist on MATTR VII. This field is empty by default, meaning no claims are persisted.
  • setIssuer : Use the interaction hook URL to set the response JWT issuer (iss). This value can be retrieved from the audience (aud) claim in the decoded redirect JWT.
  • setAudience : Use your MATTR VII tenant URL to set the response JWT audience (aud). The value can be retrieved from the issuer (iss) claim in the decoded redirect JWT.
  • setProtectedHeader : Set the protected JWT header. In this case, it includes the algorithm (alg: "HS256") and the token type (typ: "JWT").
  • setIssuedAt : Set the “issued at” (iat) claim to the current time. This indicates when the JWT was signed.
  • setExpirationTime : Set the JWT expiration time (exp). In this case, it is set to expire one minute after it is issued.

Adding the signed JWT to the redirect URL

The resulting signed JWT must be added as a query parameter to the redirect URL by your Interaction hook component:

HTTP
https://learn.vii.au01.mattr.global/v1/oauth/interaction/hJvfiSp3eEGyb/interactionhook/callback?session_token=RESPONSE_JWT

Once the user completes the interaction hook component journey and they are redirected to this URL, MATTR VII will use the RESPONSE_JWT to verify the redirect and continue the OID4VCI workflow.

Handling Errors

If your Interaction hook component determines that the user should not be allowed to continue with the issuance journey (for example, they’ve failed a biometrics test), you can return an error 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:

TypeScript
import { SignJWT } from 'jose'
 
const secret = Buffer.from('<SHARED_SECRET>', 'base64')
 
const jwt = await new SignJWT({
    state: 'hJvfiSp3eEGybd',
    error: {
        message: 'Identity assurance failed'
    }
})
    .setIssuer('https://example-webapp.com')
    .setAudience('https://learn.vii.au01.mattr.global')
    .setProtectedHeader({ alg: 'HS256', typ: 'JWT' })
    .setIssuedAt()
    .setExpirationTime('1m')
    .sign(secret)

When this JWT object is included in the redirect as a query parameter, it indicates MATTR VII to terminate the issuance workflow.