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:
- Configure a MATTR VII Interaction hook.
- Verify the Interaction hook redirect JWT.
- Use the decoded payload.
- Sign the Interaction hook response JWT.
- Handling errors
Configure a MATTR VII Interaction hook
Request
Make a request of the following structure to configure an Interaction hook:
PUT /v1/openid/configuration
Request body
{
"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. Whenfalse
, 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
{
"interactionHook": {
"url": "https://example-webapp.com/callback",
"claims": [],
"sessionTimeoutInSec": 1200,
"disabled": false,
"secret": "dGtUrijBOT6UUJ8JO4kAFyGfhahDlVVeIk/sPbWTa7c="
}
}
secret
: Use this secret to verify the interaction hook redirect.
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:
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:
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
- 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:
{
"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:
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 theclaimsToPersist
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:
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:
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.