light-mode-image
Learn
Authorization Code flowInteraction hook

How to set up an Interaction hook

An Interaction hook enables you to redirect users to a custom component during the OID4VCI Authorization Code flow. This redirect happens after the user authenticates but before the credential is issued, allowing you to introduce custom interactions such as collecting additional information, performing MFA or biometric checks, or presenting terms of service.

This guide walks you through the steps required to configure and integrate an Interaction hook into your credential issuance workflow.

Prerequisites

We recommend using a web application as your Interaction hook component, as this is more compatible with most scenarios.

Overview

Setting up an Interaction hook comprises the following steps:

  1. Configure the Interaction hook on your tenant.
  2. Verify the Interaction hook redirect.
  3. Process the interaction and redirect back to MATTR VII.

Configure the Interaction hook

Configure your MATTR VII tenant with the URL of your Interaction hook component. This tells MATTR VII where to redirect users after they authenticate.

Each tenant can only have a single Interaction hook configured. If your workflow requires multiple custom interactions, they must be implemented within the same component.

  1. Sign in to the MATTR Portal.
  2. In the left navigation, expand Credential Issuance.
  3. Select Interaction hook.
  4. In Redirect URL post user completion, enter the publicly accessible URL of your Interaction hook component.
  5. Optionally configure the following:
    • Claims: Select which user claims from the Authentication Provider should be included in the session token sent to your component.
    • Session timeout: Set the session duration (in seconds) for the interaction. If not set, the default environment session duration applies.
  6. Set Status to Enabled.
  7. Select Update to save the configuration.
  8. Copy the displayed Secret. You will need this to verify and sign JWTs.

Make a PUT request to configure the Interaction hook:

Request
PUT /v1/openid/configuration
Request body
{
    "interactionHook": {
        "url": "https://your-interaction-hook.example.com",
        "claims": ["first_name", "last_name", "email"],
        "sessionTimeoutInSec": 1200,
        "disabled": false
    }
}
  • url : The publicly accessible URL of your Interaction hook component. Must use HTTPS, must not be an IP address, and must not include query parameters.
  • claims : An array of user attribute names from the Authentication Provider that will be included in the session token sent to your component. Claims can only contain alphanumeric characters, _, or -. If empty or not defined, no claims are sent.
  • sessionTimeoutInSec : The session duration in seconds (minimum: 300, maximum: 7200). Once a session expires, the user is shown an error when redirected. If not specified, the default environment session duration applies.
  • disabled : Set to false to enable the Interaction hook. When true (default), the hook is disabled and users are not redirected.

Response

Response body
{
    "interactionHook": {
        "url": "https://your-interaction-hook.example.com",
        "claims": ["first_name", "last_name", "email"],
        "sessionTimeoutInSec": 1200,
        "disabled": false,
        "secret": "dGtUrijBOT6UUJ8JO4kAFyGfhahDlVVeIk/sPbWTa7c="
    }
}
  • secret : A Base64-encoded 32-byte HMAC secret. Store this securely — you will use it to verify incoming JWTs and sign response JWTs.

Once the Interaction hook is enabled, any OID4VCI Authorization Code issuance workflow on your tenant will redirect the user to your component after authentication.

Verify the Interaction hook redirect

When MATTR VII redirects the user to your component, it appends a signed JWT as a session_token query parameter:

https://your-interaction-hook.example.com?session_token=eyJhbGciOiJIUzI1NiIs...

Your component must verify this JWT using the secret obtained during configuration to confirm that the request originates from MATTR VII:

  1. Extract the session_token query parameter from the incoming request URL.
  2. Verify the JWT signature using the Base64-decoded secret with the HS256 algorithm.
  3. Validate the following JWT claims:
    • iss : Must match your MATTR VII tenant URL.
    • aud : Must match your Interaction hook URL.
    • exp : Must not be expired.
  4. If verification fails, reject the request.

Decoded JWT payload structure:

Example decoded session_token payload
{
    "state": "hJvfiSp3eEGybd-KmL8ja",
    "scopes": ["ldp_vc:CourseCredential"],
    "claims": {
        "first_name": "Jane",
        "last_name": "Doe",
        "email": "jane@example.com"
    },
    "authenticationProvider": {
        "url": "https://your-idp.example.com",
        "subjectId": "auth0|123456789"
    },
    "redirectUrl": "https://your-tenant.vii.mattr.global/v1/oauth/interaction/hJvfiSp3eEGybd-KmL8ja/interactionhook/callback",
    "sub": "a44a7f92-c61e-48a0-88b6-863eeeb58394",
    "aud": "https://your-interaction-hook.example.com",
    "iss": "https://your-tenant.vii.mattr.global",
    "iat": 1673910963,
    "exp": 1673911263
}
  • state: Unique session identifier. Must be included in your response JWT.
  • claims: User claims from the Authentication Provider (based on your configuration).
  • redirectUrl: The URL to redirect the user back to after the interaction hook custom component completes.
  • authenticationProvider.url: The Authentication Provider URL.
  • authenticationProvider.subjectId: The user's subject identifier with the Authentication Provider.

The session token is passed in the URL and is subject to browser URL character limits. Avoid transferring large data (such as images) to or from the Interaction hook component.

Redirect back to MATTR VII

Once the user completes the interaction, your component must redirect them back to MATTR VII to continue the issuance flow. This involves signing a new JWT and including it as a query parameter.

Steps to complete the redirect:

  1. Sign a response JWT using the same secret (Base64-decoded) with the HS256 algorithm:

    Response JWT payload
    {
        "iss": "https://your-interaction-hook.example.com",
        "aud": "https://your-tenant.vii.mattr.global",
        "state": "hJvfiSp3eEGybd-KmL8ja",
        "claims": {
            "preferred_name": "Jane Smith"
        },
        "claimsToPersist": ["preferred_name"],
        "iat": 1673911000,
        "exp": 1673911060
    }
    • iss (required): Your Interaction hook URL.
    • aud (required): Your MATTR VII tenant URL.
    • state (required): The state value from the original session token. This links the response to the correct issuance session.
    • claims (optional): An object containing claims to include in the issued credential. These values can override claims from the Authentication Provider.
    • claimsToPersist (optional): An array of claim names from claims that should be persisted on the MATTR VII tenant for future use. If empty or omitted, no claims are persisted.
    • iat (required): Issued-at timestamp.
    • exp (required): Expiration timestamp. Use a short window (e.g. 1 minute) to minimize the risk of token replay.
  2. Redirect the user to the redirectUrl from the original session token, appending the signed JWT as a session_token query parameter:

    https://your-tenant.vii.mattr.global/v1/oauth/interaction/hJvfiSp3eEGybd-KmL8ja/interactionhook/callback?session_token=eyJhbGciOiJIUzI1NiIs...

MATTR VII validates the response JWT and uses the returned claims according to your Credential configuration claim mappings.

Handling errors

If your component determines that the user should not proceed with credential issuance (for example, they failed a biometrics check), you can signal an error by including an error object in the response JWT payload instead of claims:

Error response JWT payload
{
    "iss": "https://your-interaction-hook.example.com",
    "aud": "https://your-tenant.vii.mattr.global",
    "state": "hJvfiSp3eEGybd-KmL8ja",
    "error": {
        "message": "Biometric verification failed"
    },
    "iat": 1673911000,
    "exp": 1673911060
}

The error object must include a message field (string). You can include additional fields alongside message, but only message is used by MATTR VII.

What happens when an error is returned:

  1. MATTR VII terminates the issuance session.
  2. The user is redirected back to the wallet application with the following error parameters appended to the redirect URI:
    • error: access_denied
    • error_description: Invalid interaction request
  3. The error.message from your JWT is included in the OPENID_INTERACTION_HOOK_FAIL analytics event. This can be used for debugging and monitoring, but is not visible to the end user.

Do not include personally identifiable information (PII) in the error.message field, as it is captured in analytics events and platform logs.

Best practices

  • Secure your component: Since the Interaction hook component must be publicly accessible, use the JWT verification mechanism to protect against unauthorized access.
  • Keep sessions short: Set sessionTimeoutInSec to an appropriate duration for your use case. Shorter sessions reduce the window for potential misuse.
  • Use short-lived response JWTs: Set the exp claim in your response JWT to a short window (e.g. 1 minute) to minimize the risk of token replay.
  • Only persist necessary claims: Use claimsToPersist selectively. Only persist claims that you need for future interactions to minimize data storage.
  • Handle expiry gracefully: If the session expires before the user completes the interaction, display a user-friendly message and guide them to restart the issuance flow.
  • Combine interactions: If you need multiple steps (e.g. biometric check followed by terms acceptance), build them into a single Interaction hook component.

What's next?

How would you rate this page?

Last updated on

On this page