npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@unqtech/age-verification-mitid

v0.4.3

Published

Frontend SDK for age verification via UNQVerify using MitID

Readme

@unqtech/age-verification-mitid

Frontend SDK for age verification using UNQVerify (MitID-powered).

🔗 Official site: aldersverificering.dk


Contents


Installation

npm install @unqtech/age-verification-mitid

TypeScript 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

  1. Go to Pages → Add New in WordPress admin
  2. Set the slug to aldersverificering (matching REDIRECT_URI above)
  3. Leave the content empty — the script handles everything
  4. 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
  • postMessage events are validated against a strict origin allowlist
  • The unqverify_token cookie is set with SameSite=Lax; Secure
  • Cookie lifetime is the greater of the JWT exp claim 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