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

@jummon/auth-react-native

v0.1.1

Published

React Native / Expo adapters for @jummon/auth's agnostic core: AsyncStorage+SecureStore storage, expo-crypto PKCE, Linking-based social-login navigation, and react-native-passkey WebAuthn. Headless-only (mode: "headless") — no hosted-redirect mode on RN.

Readme

@jummon/auth-react-native

React Native / Expo adapters for @jummon/auth's platform-agnostic core (@jummon/auth/core). Ships the same headless in-app login (mode: "headless" — password, passkey, social) @jummon/auth ships for the web, wired to RN-native storage/crypto/navigation/WebAuthn instead of window/navigator/localStorage.

Headless-only. RN has no addressable URL bar to redirect to a hosted login page and back, so this package never offers a "redirect" mode — createJummonAuthReactNative() always builds a headless client.

Install

npm install @jummon/auth @jummon/auth-react-native
# + whichever native modules you'll pass in (see below) — none are hard
# dependencies of this package, you choose the versions your app already pins:
npm install @react-native-async-storage/async-storage expo-secure-store expo-crypto
npm install react-native-passkey # optional — omit if passkeys aren't Wave-1 for your app

This package never imports any of those native modules itself — every adapter is a small factory function that takes the ALREADY-IMPORTED module (or an object shaped like it) as a constructor argument. That's why none of them are hard dependencies: you control exactly which native module satisfies each shape, including a react-native-keychain-backed shim instead of expo-secure-store (see SecureStorageLike below) on a bare-RN app.

Quick start

import AsyncStorage from "@react-native-async-storage/async-storage";
import * as SecureStore from "expo-secure-store";
import * as ExpoCrypto from "expo-crypto";
import { Linking } from "react-native";
import { Passkey } from "react-native-passkey"; // optional
import { createJummonAuthReactNative } from "@jummon/auth-react-native";
import { JummonAuthProvider, useHeadlessAuthFlow, useJummonAuth } from "@jummon/auth/react";

const client = createJummonAuthReactNative(
  {
    tenant: "acme", // slug, never the tenant UUID
    clientId: "acme-app",
    redirectUri: "acme://auth/callback", // your app's registered custom scheme / deep link
    issuerHost: "idm.jummon.com", // "idm.jummon.dev" in the dev environment
  },
  {
    asyncStorage: AsyncStorage,
    secureStore: SecureStore,
    expoCrypto: ExpoCrypto,
    linking: Linking, // or `import * as Linking from "expo-linking"`
    passkey: Passkey, // omit entirely if you have no passkey story yet
  },
);

export function App() {
  return (
    <JummonAuthProvider client={client}>
      <LoginScreen />
    </JummonAuthProvider>
  );
}

function LoginScreen() {
  const { snapshot, start, submitPassword, startPasskeyLogin, startSocialLogin, submitMfaCode } =
    useHeadlessAuthFlow();

  React.useEffect(() => {
    start();
  }, []);

  // Render your OWN UI off `snapshot.status` — see @jummon/auth's README for
  // the full state machine (needs_credentials, needs_mfa, needs_required_action, …).
  return null;
}

function Profile() {
  const { user, signOut } = useJummonAuth();
  // ...
}

JummonAuthProvider/useJummonAuth/useHeadlessAuthFlow are the SAME exports the web package (@jummon/auth/react) ships — this package only supplies the client you hand to the provider's client prop; the React binding itself is platform-agnostic and never imported here.

Social login / deep-link return

redirect() opens the system browser (Linking.openURL — never an in-app WebView; Google and other IdPs block embedded-WebView OAuth outright). Register your redirectUri's scheme (acme://auth/callback above) as a deep link in your app config (Expo: app.json's scheme; bare RN: the platform's own URL-scheme/associated-domain setup) so the OS routes the provider's callback back into your app. On the screen your redirectUri points at, call useHeadlessAuthFlow().resume() on mount — same call the web package's social-redirect flow makes, just resolved off the RN Linking adapter's cold-start/'url'-event tracking instead of window.location.

Storage split

  • Non-secret, short-lived flow-resume state → AsyncStorage.
  • Long-lived session tokens (access_token/refresh_token) → your secure backend, routed by key prefix (createReactNativeStorage, exported from ./adapters too). secureStore accepts either expo-secure-store's {getItemAsync,setItemAsync,deleteItemAsync} shape, or anything shaped like AsyncStorage ({getItem,setItem,removeItem}) — wrap react-native-keychain (or another bare-RN secure store) into that second shape if you're not on Expo.

Known runtime gotcha — atob/btoa/Buffer (fixed, B1)

@jummon/auth's base64/base64url codec (src/internal/base64.ts, shared via the @jummon/auth/core re-export this package imports from — see adapters/webauthn.ts) is dependency-free (no atob/btoa/Buffer assumption) specifically because Hermes (RN's default JS engine) doesn't ship those globals. This package never vendors its own copy — every base64 operation in this package's own code (WebAuthn's binary field encoding/decoding) goes through that one shared implementation. If your app also pulls in @jummon/auth's web-oriented code paths some other way, make sure you're only importing @jummon/auth/core (as this package does) — the main @jummon/auth entry and @jummon/auth/react's non-headless bits are web-oriented and may assume browser globals this package's own code never touches.

Metro module resolution (B2)

Metro (RN's bundler) only honors package.json's exports map with unstable_enablePackageExports enabled, which isn't default across the react-native >=0.70 peer range this package targets. @jummon/auth ships root-level proxy files (core.js/core.d.ts, react.js/react.d.ts at the package root, re-exporting dist/core.js/dist/react.js) so import ... from "@jummon/auth/core" resolves via plain Node-style resolution too — no Metro config change needed on your end for this package's own imports to work, and none needed in your app either unless you import @jummon/auth/core/@jummon/auth/react directly yourself.

Passkeys

react-native-passkey's request/response objects are JSON (every binary field is already a base64url string) — this package's WebAuthn adapter (createReactNativeWebAuthn) is the translation layer between that JSON shape and the DOM-shaped PublicKeyCredential the agnostic core speaks. Omit passkey from createReactNativePlatformAdapters()/ createJummonAuthReactNative() entirely if passkeys aren't in scope yet — registerPasskey()/startPasskeyLogin() degrade to a clear passkey_origin_unsupported/passkey_failed error instead of crashing.

Risk signals

Opt-in client risk-signal collection (initiative #85 — see @jummon/auth's README for the full allowlist/spec) works the same as on web: pass collectRiskSignals: true in the options you give createJummonAuthReactNative(). device_id/flow_ms/schema need no RN dependency at all (computed by the agnostic core against your asyncStorage/expoCrypto deps); tz has a built-in Intl fallback that works out of the box on modern Hermes; lang/device_class have no first-party RN API, so supply them yourself (RN has no built-in navigator.language equivalent):

import * as Localization from "expo-localization"; // or react-native-localize

const client = createJummonAuthReactNative(
  { tenant: "acme", clientId: "acme-app", redirectUri: "acme://auth/callback", collectRiskSignals: true },
  {
    asyncStorage: AsyncStorage,
    secureStore: SecureStore,
    expoCrypto: ExpoCrypto,
    linking: Linking,
    riskSignals: {
      getLanguage: () => Localization.getLocales()[0]?.languageTag ?? null,
      getDeviceClass: () => (Localization.getLocales()[0] /* or Dimensions-based heuristic */ ? "mobile" : null),
    },
  },
);

Omit riskSignals entirely for the Intl-only fallback (timezone only) — createReactNativeRiskSignals() never throws and every field degrades to null rather than crashing when a dep is missing or its callback throws.