Using the presentation request hook
Learn how to use the optional onPresentationRequest hook to run your own logic each time a presentation request is issued or refreshed during a remote verification session.
When your web application calls requestCredentials(), the Verifier Web SDK creates a presentation
session on your MATTR VII verifier tenant and then drives the wallet interaction on your behalf.
Between those two points the SDK holds a live OpenID4VP authorization request that your application
never sees. If you need to record that request, emit an audit event, or start a timer at the moment
it is issued, there is no result to hook into yet.
The onPresentationRequest parameter on requestCredentials() gives you that hook. The SDK invokes
it with the current presentation request as soon as the session is created, and again whenever the
request is regenerated. The hook can be synchronous or asynchronous, and the SDK awaits it before
continuing.
When to use the hook
Use onPresentationRequest when your application needs to act on the request itself rather than on
the verification result. Common cases include:
- Mirroring the
authRequestUriinto your own system, so another screen or a back office view can present it. - Emitting analytics or audit records at the moment a request is issued to a wallet.
- Starting a timer or progress indicator that tracks how long a request has been outstanding.
- Reacting to cross-device QR code refreshes, for example by updating your own rendering of the current request.
You do not need the hook if your application only consumes the final verification result. Refer to
Handling verification results
for that. If what you need is a correlation reference that travels with the session and comes back
with the result, use the state parameter instead. Refer to
Correlating verification sessions with your system.
When the hook fires
The first invocation happens for every session type, immediately after the presentation session is created and before the wallet interaction begins. Only cross-device sessions invoke the hook again, because they are the only flow with a request URI that is regenerated while the session is running.
| Session type | Invocations |
|---|---|
| Same-device | Once, after the session is created and before the browser redirects to the wallet. |
| Cross-device | Once after the session is created, then again every time the QR code in the iframe refreshes. |
| Digital Credentials API | Once, after the session is created. |
A cross-device session can refresh its QR code many times, so treat the hook as something that
may run repeatedly with a different authRequestUri on each invocation. Make the work inside it
safe to repeat, and do not assume the first invocation is the only one.
The hook payload
The hook receives the current presentation request. The payload is a discriminated union on type:
type PresentationRequest =
| {
type: "openid4vp";
sessionId: string;
authRequestUri: string;
}
| {
type: "digital-credentials-api";
sessionId: string;
};OpenID4VP sessions, which cover both same-device and cross-device flows, expose sessionId and
authRequestUri. Digital Credentials API sessions expose sessionId only, because there is no
wallet-facing request URI to hand back in that flow.
Narrow on request.type before reading authRequestUri. These payload types are not exported from
the package, so check the string literal rather than importing the union:
onPresentationRequest: (request) => {
if (request.type === "openid4vp") {
// request.authRequestUri is available here.
}
},Setting the hook when starting a session
Pass onPresentationRequest alongside the other options when calling requestCredentials():
const options: MATTRVerifierSDK.RequestCredentialsOptions = {
credentialQuery: [credentialQuery],
challenge: MATTRVerifierSDK.utils.generateChallenge(),
openid4vpConfiguration: {
redirectUri: window.location.origin,
walletProviderId: process.env.NEXT_PUBLIC_WALLET_PROVIDER_ID,
},
onPresentationRequest: async (request) => {
if (request.type === "openid4vp") {
await fetch("/api/presentation-requests", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
sessionId: request.sessionId,
authRequestUri: request.authRequestUri,
}),
});
}
},
};
const results = await MATTRVerifierSDK.requestCredentials(options);The SDK awaits the hook before it continues, so a slow hook delays the presentation the user is waiting on. Keep the work inside it short, and hand anything long running to your own backend.
Error handling
The hook runs as part of the presentation flow, so a failure inside it ends the presentation. If the hook throws, or the promise it returns rejects, the SDK tears the session down:
- The session is aborted on your verifier tenant.
- For cross-device sessions, the iframe holding the QR code is closed.
requestCredentials()resolves with anOnPresentationRequestFailederror.
This applies to every invocation, whether it was the initial one or a later cross-device refresh.
requestCredentials() returns a Result, so a failed hook surfaces as an error value rather than a
thrown exception. The cause property carries whatever your hook threw:
const results = await MATTRVerifierSDK.requestCredentials(options);
if (results.isErr()) {
const { type, cause } = results.error;
if (type === MATTRVerifierSDK.RequestCredentialsErrorType.OnPresentationRequestFailed) {
// cause holds the error your hook threw or rejected with.
console.error("Presentation aborted by onPresentationRequest", cause);
}
}Aborting is the default behavior. If the work in your hook is not essential to the verification, catch the error inside the hook so that a failure in your own system does not end the user's presentation.
onPresentationRequest: async (request) => {
try {
await recordPresentationRequest(request);
} catch (error) {
// Handle the error here so requestCredentials() continues with the presentation.
console.error("Failed to record presentation request", error);
}
},When the hook is not supplied
onPresentationRequest is optional and additive. If you do not pass it:
- No callback is made at any point in the session.
- The presentation flow is unchanged in same-device, cross-device, and Digital Credentials API sessions.
requestCredentials()never returns anOnPresentationRequestFailederror.
Existing integrations that do not pass the hook see no change in behavior.
Next steps
- Review the Verifier Web SDK API reference for complete type definitions.
- See Handling verification results
for the shape of the result that
requestCredentials()resolves with. - See Correlating verification sessions with your system
for the
stateparameter, which is the right tool when you need a correlation reference rather than a callback.
How would you rate this page?
Last updated on