@unqtech/age-verification-mitid
v0.4.3
Published
Frontend SDK for age verification via UNQVerify using MitID
Maintainers
Readme
@unqtech/age-verification-mitid
Frontend SDK for age verification using UNQVerify (MitID-powered).
🔗 Official site: aldersverificering.dk
Contents
- Installation
- Quick start (npm)
- Outcome codes
init(config)options- Other functions
- Backwards compatibility
- CDN / No-bundler usage
- WooCommerce integration
- Security
- License
Installation
npm install @unqtech/age-verification-mitidTypeScript users can also import the types directly:
import type { UnqVerifyConfig, VerificationErrorCode, VerificationOutcome } from '@unqtech/age-verification-mitid'Quick start (npm)
import { init, startVerificationWithRedirect, isVerified } from '@unqtech/age-verification-mitid'
init({
publicKey: 'pk_test_abc123',
ageToVerify: 18,
redirectUri: 'https://yourapp.com/verify-result',
onVerified: (payload) => console.log('Verified!', payload),
onDenied: (outcome) => alert('You do not meet the age requirement.'),
onCancelled: (outcome) => console.info('Cancelled:', outcome.code),
onError: (outcome) => console.error('Error:', outcome.code, outcome.message),
})
if (!isVerified()) {
startVerificationWithRedirect()
// or: startVerificationWithPopup()
}On the page your redirectUri points to:
import { handleRedirectResult } from '@unqtech/age-verification-mitid'
await handleRedirectResult({
onVerified: (payload) => { /* redirect user back */ },
onDenied: (outcome) => { /* show denied message */ },
onError: (outcome) => console.error(outcome.code, outcome.message),
targetOrigin: 'https://yourapp.com', // recommended in popup mode
})Outcome codes
Every non-success path provides a VerificationOutcome object:
interface VerificationOutcome {
code: VerificationErrorCode // stable, machine-readable
message: string
raw?: unknown
}| Code | Callback | When |
|---|---|---|
| UNDER_AGE | onDenied | MitID returned verification_result: false. Covers both genuine under-age and user opting out at the MitID screen — MitID sends the same response for both. |
| USER_CANCELLED | onCancelled | User cancelled inside the MitID flow |
| POPUP_CLOSED | onCancelled | User closed the popup window manually |
| POPUP_TIMEOUT | onCancelled | Popup open > 5 minutes without result |
| POPUP_BLOCKED | onError | Browser blocked the popup |
| NETWORK_ERROR | onError | API call failed |
| TOKEN_INVALID | onError | JWT missing, expired, or invalid signature |
| UNTRUSTED_ORIGIN | onError | postMessage received from an untrusted origin |
| UNKNOWN_ERROR | onError | Unexpected error |
init(config) options
| Option | Type | Required | Description |
|---|---|---|---|
| publicKey | string | yes | Your pk_test_... or pk_live_... key |
| ageToVerify | number | yes | Minimum age threshold |
| redirectUri | string | yes | HTTPS URL the user returns to after MitID |
| onVerified | (payload) => void | yes | Called on successful verification |
| onDenied | (outcome) => void | no | Age requirement not met |
| onCancelled | (outcome) => void | no | Popup closed or timed out |
| onError | (outcome) => void | no | Technical/system error |
| onFailure | (error?) => void | no | Legacy catch-all (always invoked alongside granular callbacks) |
| debug | boolean | no | Verbose SDK logging (default false) |
Other functions
| Function | Description |
|---|---|
| startVerificationWithRedirect() | Full-page redirect flow |
| startVerificationWithPopup(popup?) | Popup flow |
| handleRedirectResult(opts) | Process result on the redirect page |
| isVerified() | true if user has a valid, non-expired token |
| getVerifiedAge() | Verified age as number, or null |
| resetVerification() | Clears the session cookie |
Backwards compatibility
onFailure is always called alongside any granular callback, so existing v0.3 integrations continue to work unchanged.
// v0.3 — still works
onFailure: (err) => showError(err)
// v0.4 — use granular callbacks instead
onDenied: (outcome) => showMessage('Come back when you are older'),
onCancelled: (outcome) => hideModal(),
onError: (outcome) => reportError(outcome.code, outcome.raw),CDN / No-bundler usage
Load the self-contained UMD build directly — no npm or build step required.
<script src="https://unpkg.com/@unqtech/age-verification-mitid@latest/dist/index.umd.js"></script>All functions are available under window.UnqVerify after the script loads.
WooCommerce integration
1 — Enqueue the script (functions.php)
add_action( 'wp_enqueue_scripts', function () {
if ( is_shop() || is_product() || is_product_category() || is_cart() || is_checkout() ) {
wp_enqueue_script(
'unqverify-sdk',
'https://unpkg.com/@unqtech/age-verification-mitid@latest/dist/index.umd.js',
[], null, true
);
}
} );2 — Initialize and gate the page
add_action( 'wp_footer', function () {
if ( ! ( is_shop() || is_product() || is_product_category() || is_cart() || is_checkout() ) ) {
return;
}
?>
<script>
(function () {
var PUBLIC_KEY = 'pk_live_YOUR_KEY';
var REDIRECT_URI = '<?php echo esc_js( home_url( '/aldersverificering/' ) ); ?>';
if ( window.location.pathname.indexOf( '/aldersverificering' ) !== -1 ) {
UnqVerify.init({
publicKey: PUBLIC_KEY,
ageToVerify: 18,
redirectUri: REDIRECT_URI,
onVerified: function () {
var returnTo = sessionStorage.getItem( 'unqverify_return' ) || '<?php echo esc_js( wc_get_page_permalink( "shop" ) ); ?>';
window.location.href = returnTo;
},
onDenied: function () {
alert( 'Du opfylder desværre ikke alderskravet.' );
},
onError: function () {
alert( 'Aldersverificering mislykkedes. Prøv venligst igen.' );
}
});
UnqVerify.handleRedirectResult({
onVerified: function () {},
onDenied: function ( outcome ) { console.warn( outcome.code ); },
onError: function ( outcome ) { console.error( outcome.code ); }
});
return;
}
UnqVerify.init({
publicKey: PUBLIC_KEY,
ageToVerify: 18,
redirectUri: REDIRECT_URI,
onVerified: function () {},
onError: function () {}
});
if ( ! UnqVerify.isVerified() ) {
sessionStorage.setItem( 'unqverify_return', window.location.href );
UnqVerify.startVerificationWithRedirect();
}
})();
</script>
<?php
} );3 — Create the verification result page
- Go to Pages → Add New in WordPress admin
- Set the slug to
aldersverificering(matchingREDIRECT_URIabove) - Leave the content empty — the script handles everything
- Register the URL as an Allowed redirect URI in your UNQVerify dashboard
Security
- All JWTs are RS256-verified against the issuer's JWKS endpoint
- Unknown issuers are always rejected
postMessageevents are validated against a strict origin allowlist- The
unqverify_tokencookie is set withSameSite=Lax; Secure - Cookie lifetime is the greater of the JWT
expclaim or 1 hour, ensuring the verification session is not lost too quickly even if the token has a short TTL
JWKS endpoints:
https://test.api.aldersverificering.dk/well-known/openid-configuration/jwks (test)
https://api.aldersverificering.dk/well-known/openid-configuration/jwks (live)License
MIT © UNQTech ApS
