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

@criipto/verify-expo

v4.0.2

Published

Accept MitID, NemID, Swedish BankID, Norwegian BankID and more logins in your Expo (React-Native) app

Readme

criipto-verify-expo

The Idura Verify Expo SDK allows your users to authenticate with a host of European eID providers. It allows your application to act as a public client, meaning it does not use a client secret, but instead employs PKCE to ensure that a malicious actor cannot intercept the authorization code.

In addition to the basic OIDC flow, the SDK also supports app switching.

Requirements

  • Expo SDK 54 or newer (ships React Native 0.81 / Kotlin 2.1.20 / AGP 8.11).
  • Android minSdkVersion 26 or newer. Expo's prebuild default is 24, so you must opt in explicitly via expo-build-properties — see Installation.
  • iOS 17.4 or newer, with use_frameworks! :linkage => :dynamic. The Idura Verify iOS SDK is distributed as a Swift Package, which requires dynamic framework linkage. The Expo plugin verifies both via expo-build-properties.
  • This module includes native code, so it will not work with Expo Go. You must use a build, for instance npx expo run:ios / npx expo run:android or EAS Build.

Both platforms delegate to the native Idura Verify SDKs (Android, iOS). Consumers on older Expo releases should stay on @criipto/verify-expo 3.x.

Installation

npm install @criipto/verify-expo expo-build-properties

Initialization

The SDK needs to be configured with two pieces of information:

  • Your Idura domain.
  • Your Idura client ID.

The SDK assumes that:

  • You will be using your Idura domain to host your redirect URL (both custom domains, *.criipto.id, and *.idura.broker domains can be used).
  • Your redirect URL will be https://[YOUR IDURA DOMAIN]/[ios|android]/callback. Currently, custom redirect URLs are not supported. Open an issue if you need it.

You should register the callback URLs in the Idura dashboard. If your domain is https://samples.criipto.id, you should register both https://samples.criipto.id/ios/callback and https://samples.criipto.id/android/callback.

Then configure both plugins in app.json. expo-build-properties must appear before @criipto/verify-expo so its overrides are applied first:

"plugins": [
  ["expo-build-properties", {
    "android": { "minSdkVersion": 26 },
    "ios": { "useFrameworks": "dynamic", "deploymentTarget": "17.4" }
  }],
  ["@criipto/verify-expo", {
    "domain": "YOUR_IDURA_DOMAIN",
    "clientID": "urn:my:application:identifier:XXXX"
  }]
]

The plugin fails expo prebuild with copy-paste-friendly errors if any of these requirements are unmet.

Getting Started

Call login() directly — there's no provider or hook to wire up. Configuration (domain, clientID) lives in app.json and is read by the native modules. Hold the result in your own state (useState, zustand, react-query — your call) since the package doesn't keep one for you:

// src/LoginButton.jsx
import { useState } from "react";
import { Button, Text } from "react-native";
import { login, OAuth2Error, UserCancelledError } from "@criipto/verify-expo";

export default function LoginButton() {
  const [claims, setClaims] = useState(null);
  const [error, setError] = useState(null);

  const handlePress = async (acrValues) => {
    try {
      const { id_token, trace_id, claims } = await login({ acrValues });
      setClaims(claims);
      setError(null);
    } catch (e) {
      if (e instanceof UserCancelledError) return; // expected; not an error condition
      setError(e);
      setClaims(null);
    }
  };

  return (
    <>
      <Button
        onPress={() => handlePress("urn:grn:authn:dk:mitid:substantial")}
        title="Login with Danish MitID"
      />
      <Button
        onPress={() => handlePress("urn:grn:authn:se:bankid:same-device")}
        title="Login with Swedish BankID"
      />
      <Button onPress={() => handlePress("urn:grn:authn:se:frejaid")} title="Login with Freja ID" />
      <Button
        onPress={() => handlePress("urn:grn:authn:no:bankid:substantial")}
        title="Login with Norwegian BankID"
      />

      {error ? <Text>An error occurred: {error.toString()}</Text> : null}
      {claims ? <Text>{JSON.stringify(claims, null, 2)}</Text> : null}
    </>
  );
}

On failure login() throws a typed error: UserCancelledError for the user dismissing the flow, OAuth2Error for IdP errors, NoSuitableBrowserError (Android-only) when no Custom Tab-capable browser is installed, plus ModuleNotConfiguredError / UnknownPromptError / IduraVerifyInternalError. All carry the SDK's trace_id where available, for correlation in the Idura dashboard.

Warming up

The native SDK is built on the first login() call, which is when OIDC discovery, the JWKS fetch and — on Android — the scan for a usable browser happen. To take that off the login path, call warmUp() from an effect on the screen that logs in:

import { useEffect } from "react";
import { warmUp } from "@criipto/verify-expo";

useEffect(() => {
  warmUp();
}, []);

It is entirely optional, never throws, and is cheap to call more than once. Because it reports nothing, a misconfigured app still fails at login() with ModuleNotConfiguredError — the native side logs the reason under the CriiptoVerifyExpo tag (logcat) or via NSLog, so you can see it while wiring up an integration.

Ephemeral sessions (iOS only)

The web view used to display the login page lets you choose between an ephemeral or a shared browser session.

  • An ephemeral session shares no cookies with the user's default browser, so the user may have to enter their login details. This is the default.
  • A shared session shares cookies with the user's default browser, so login details may be remembered between logins. However, the system presents a permission dialog ("'Your App' wants to use 'idura.broker' to sign in") each time the user logs in.

The default value is to use an ephemeral session.

It is up to you to decide which flow is better, based on the UX requirements of your application. Not all eIDs require the user to enter anything in the webview — for example, Swedish BankID takes the user directly to their authenticator app. For this reason, you may also want to use a shared session for some eIDs but not others. Pass preferEphemeralSession on the login() call to override per-flow:

await login({
  acrValues: "urn:grn:authn:dk:mitid:substantial",
  preferEphemeralSession: false, // opt into a shared browser session
});

Danish MitID supports a re-authentication flow, so you do not need to rely on a shared browser session if you need to re-authenticate the user with MitID.

On Android the parameter is silently ignored: Custom Tab sessions don't share cookies with the browser, and the Android SDK doesn't expose the choice.

Idura

Learn more about Idura and sign up for your free developer account at idura.eu.