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

@novahelm/auth

v2026.6.2

Published

NovaAuth — full-stack authentication (argon2 + WebAuthn + JWT) for web and mobile.

Downloads

778

Readme

@novahelm/auth

Drop-in authentication for NovaHelm — NovaAuth, the first-party auth system with support for email/password, OAuth, magic links, passkeys, 2FA, phone/SMS, anonymous auth, enterprise SSO, and organizations. Works across web (Next.js / Vite / any React host) and mobile (Expo/React Native) with cookie-based and Bearer token sessions respectively.


Quick Start

pnpm add @novahelm/auth
// server — create the auth instance
import { createAuth } from "@novahelm/auth/server";

const auth = createAuth({
  db: drizzleClient,
  secret: env.NOVA_AUTH_SECRET,
  baseUrl: env.APP_URL,
  providers: {
    google: { clientId: env.GOOGLE_ID, clientSecret: env.GOOGLE_SECRET },
    github: { clientId: env.GITHUB_ID, clientSecret: env.GITHUB_SECRET },
  },
  enableMagicLink: true,
  enableTwoFactor: true,
});
// client — create the web auth client
import { createAuthClient } from "@novahelm/auth/client";

const authClient = createAuthClient({
  baseUrl: "http://localhost:3000",
});

// Use auth hooks
const { data: session } = authClient.useSession();
await authClient.signIn.email({ email, password });
await authClient.signUp.email({ name, email, password });
await authClient.signOut();

Subpath Exports

| Import path | Entry point | Purpose | |-------------|-------------|---------| | @novahelm/auth | src/index.ts | Core auth factory, permissions, API key utilities | | @novahelm/auth/server | src/server.ts | createAuth() — server-side NovaAuth factory with all plugins | | @novahelm/auth/client | src/client.ts | createAuthClient() and createNativeAuthClient() factories | | @novahelm/auth/edge | src/edge.ts | getSessionFromCookie() — edge-runtime session parsing (no DB) | | @novahelm/auth/components | src/components.ts | 16 headless auth UI components | | @novahelm/auth/react | src/react.tsx | Drop-in React provider, hooks, and pre-built auth components | | @novahelm/auth/nextjs | src/nextjs.tsx | createAuthPages() — catch-all route factory for Next.js | | @novahelm/auth/nextjs/middleware | src/nextjs-middleware.ts | withNovaAuth() — edge middleware for route protection | | @novahelm/auth/native | src/native.tsx | Expo/React Native provider, hooks, and screen wrappers |


Server Setup

createAuth() returns a NovaAuth instance with the database adapter and all configured plugins. Register it in the Nova registry via initNova().

import { createAuth, type AuthConfig } from "@novahelm/auth/server";

const auth = createAuth({
  db: drizzleClient,
  secret: env.NOVA_AUTH_SECRET,
  baseUrl: env.APP_URL,

  // OAuth providers (all optional)
  providers: {
    google:    { clientId: "...", clientSecret: "..." },
    github:    { clientId: "...", clientSecret: "..." },
    discord:   { clientId: "...", clientSecret: "..." },
    apple:     { clientId: "...", clientSecret: "..." },
    microsoft: { clientId: "...", clientSecret: "...", tenantId: "..." },
    facebook:  { clientId: "...", clientSecret: "..." },
    twitter:   { clientId: "...", clientSecret: "..." },
    linkedin:  { clientId: "...", clientSecret: "..." },
  },

  // Feature toggles
  enableMagicLink: true,       // Passwordless magic link (default: true)
  enableTwoFactor: true,       // TOTP two-factor auth
  enablePasskey: true,         // WebAuthn / passkey
  enableEmailOtp: true,        // Email OTP verification
  enableAnonymous: true,       // Anonymous / guest auth
  enablePhoneAuth: true,       // Phone / SMS OTP
  enableHaveIBeenPwned: true,  // Password breach checking
  enableSSO: true,             // Enterprise SAML 2.0 + OIDC

  // Callbacks
  onUserCreated: async (user) => {
    await welcomeEmail(user.email);
  },

  // Session config
  sessionExpiresIn: 60 * 60 * 24 * 7, // 7 days (default)
});

Client Setup

Web (React / Next.js)

import { createAuthClient } from "@novahelm/auth/client";

export const authClient = createAuthClient({
  baseUrl: process.env.NEXT_PUBLIC_APP_URL!,
});

The client provides hooks: useSession(), signIn.email(), signIn.oauth(), signUp.email(), signOut(), and more.

Mobile (Expo / React Native)

import { createNativeAuthClient } from "@novahelm/auth/client";
import * as SecureStore from "expo-secure-store";

export const authClient = createNativeAuthClient({
  baseUrl: "https://api.example.com",
  secureStorage: {
    getItem: SecureStore.getItemAsync,
    setItem: SecureStore.setItemAsync,
    removeItem: SecureStore.deleteItemAsync,
  },
});

Mobile clients use Bearer token auth with secure storage instead of cookies. The storage adapter must implement getItem, setItem, and removeItem.


React Provider & Components

The /react subpath provides a complete drop-in auth UI for web apps.

Provider

import { NovaAuthProvider } from "@novahelm/auth/react";

export function App({ children }) {
  return (
    <NovaAuthProvider
      baseUrl="http://localhost:3000"
      oauthProviders={["google", "github"]}
    >
      {children}
    </NovaAuthProvider>
  );
}

Hooks

import { useAuth } from "@novahelm/auth/react";

function Dashboard() {
  const { user, isAuthenticated, isLoading, signOut } = useAuth();

  if (isLoading) return <Spinner />;
  if (!isAuthenticated) return <Redirect to="/auth/sign-in" />;

  return <p>Welcome, {user.name}</p>;
}

Pre-built Components

| Component | Description | |-----------|-------------| | SignIn | Sign-in form with email/password, OAuth, passkey support. Modes: page or modal | | SignUp | Sign-up form with name, email, password, and OAuth | | UserButton | Avatar dropdown with profile link and sign-out | | UserProfile | Full profile management (info, password, 2FA, sessions, connected accounts, danger zone) | | SignedIn | Render children only when authenticated | | SignedOut | Render children only when not authenticated | | ProtectedRoute | Redirect to sign-in if unauthenticated |

Modal components have .Trigger sub-components for inline use:

import { SignIn, SignedIn, SignedOut, UserButton } from "@novahelm/auth/react";

<SignedOut>
  <SignIn mode="page" afterSignInUrl="/dashboard" />
</SignedOut>

<SignedIn>
  <UserButton afterSignOutUrl="/" />
</SignedIn>

Next.js Integration

Auth Pages (Catch-All Route)

Create a single catch-all route that handles sign-in, sign-up, forgot-password, reset-password, verify-email, and profile pages:

// app/auth/[[...slug]]/page.tsx
import { createAuthPages } from "@novahelm/auth/nextjs";

export default createAuthPages({
  afterSignInUrl: "/dashboard",
  afterSignUpUrl: "/dashboard",
  logo: <MyLogo />,
});

This maps URL slugs to pages automatically: /auth/sign-in, /auth/sign-up, /auth/forgot-password, /auth/reset-password, /auth/verify-email, /auth/profile.

Edge Middleware

Protect routes at the edge without a database round-trip:

// middleware.ts
import { withNovaAuth } from "@novahelm/auth/nextjs/middleware";

export default withNovaAuth({
  publicRoutes: ["/", "/auth/*", "/api/auth/*", "/pricing"],
  signInUrl: "/auth/sign-in",
  secret: process.env.NOVA_AUTH_SECRET, // enables HMAC signature validation
});

export const config = { matcher: ["/((?!_next|.*\\..*).*)"] };

When secret is provided, the middleware validates the session cookie's HMAC-SHA256 signature and checks expiration using only the Web Crypto API (no DB). Without secret, it falls back to a simple cookie-presence check.


Expo / React Native

import { NovaAuthProvider, useNovaAuth, SignedIn, SignedOut, ProtectedRoute } from "@novahelm/auth/native";
import { SignInScreen, SignUpScreen } from "@novahelm/auth/native";
import * as SecureStore from "expo-secure-store";

const storage = {
  getItem: SecureStore.getItemAsync,
  setItem: SecureStore.setItemAsync,
  removeItem: SecureStore.deleteItemAsync,
};

// Root layout
<NovaAuthProvider
  baseUrl="https://api.example.com"
  storage={storage}
  oauthProviders={["google", "apple"]}
>
  <SignedIn>
    <HomeScreen />
  </SignedIn>
  <SignedOut>
    <SignInScreen logo={<Logo />} onNavigate={(screen) => router.push(`/${screen}`)} />
  </SignedOut>
</NovaAuthProvider>

// Protected route with redirect
<ProtectedRoute redirectTo="/sign-in" fallback={<LoadingSpinner />}>
  <DashboardScreen />
</ProtectedRoute>

Headless Components

The /components subpath exports 16 unstyled auth components for custom UIs:

| Component | Description | |-----------|-------------| | OAuthButtons | Social login button set | | EmailVerification | Email verification flow | | ResetPasswordForm | Password reset form | | ForgotPasswordForm | Forgot password form | | EmailOtpVerify | Email OTP input | | PasskeySetup | Passkey registration | | PasskeySignIn | Passkey authentication | | PhoneSignIn | Phone/SMS sign-in | | ProfileForm | User profile editor | | PasswordChangeForm | Password change form | | TwoFactorSetup | 2FA TOTP setup with QR code | | ActiveSessions | Session management list | | ConnectedAccounts | Linked OAuth account management | | DataExport | User data export request | | DangerZone | Account deletion | | ApiKeyManager | API key CRUD interface |


Permissions & Authorization

The middleware module provides role-based access control and plan gating:

import {
  hasPermission,
  requirePermission,
  requirePlan,
  requireFeature,
  checkLimit,
} from "@novahelm/auth";

// Check permissions
const canEdit = await hasPermission(userId, "posts.write");

// Guard — throws NovaError("FORBIDDEN") if denied
await requirePermission(userId, "posts.write", "posts.delete");

// Plan gating — throws NovaError("PLAN_REQUIRED") if wrong plan
await requirePlan(userId, "pro", "enterprise");

// Feature gating — checks plan.features array
await requireFeature(userId, "ai-chat");

// Usage limits — returns { allowed, limit } without throwing
const { allowed, limit } = await checkLimit(userId, "api-calls", currentCount);

The system.manage permission acts as a wildcard and satisfies any permission check.


API Key Management

Generate, hash, and validate API keys for programmatic access:

import { generateApiKey, validateApiKey, checkApiKeyScope, VALID_API_KEY_SCOPES } from "@novahelm/auth";

// Generate a new key (show the raw key to the user once)
const { key, hash, prefix } = generateApiKey("sk_live");
// key:    "sk_live_a1b2c3..." (full key — show once)
// hash:   "abc123..."         (SHA-256 — store in DB)
// prefix: "sk_live_a1b2"      (identification prefix)

// Validate an incoming key (checks DB, updates lastUsedAt)
const ctx = await validateApiKey(incomingKey);
if (!ctx) throw new Error("Invalid API key");
// ctx: { keyId, userId, permissions, rateLimit }

// Check scope
const allowed = checkApiKeyScope("collections:read", ctx.permissions);

Available scopes: collections:read, collections:write, media:read, media:upload, schema:read, ai:chat, * (full access).


Edge Session Parsing

Parse NovaAuth session cookies without a database connection — useful for edge middleware and serverless functions:

import { getSessionFromCookie, type EdgeSession } from "@novahelm/auth/edge";

const session = await getSessionFromCookie(
  request.headers.get("cookie") ?? "",
  process.env.NOVA_AUTH_SECRET!,
);

if (session) {
  // session: { userId, expiresAt, role, planId }
}

Uses Web Crypto API only (edge-compatible). Validates HMAC-SHA256 signature and checks expiration.


Session Handling

| Platform | Transport | Storage | |----------|-----------|---------| | Web (Next.js / React) | HTTP-only cookies | Browser cookie jar | | Mobile (Expo / React Native) | Authorization: Bearer <token> header | Secure storage (e.g. expo-secure-store) |

Sessions default to 7-day expiration with daily refresh. Cookie caching is enabled with a 5-minute TTL.


API Reference

| Export | Subpath | Description | |--------|---------|-------------| | createAuth(config) | /server | Create NovaAuth instance with database adapter | | createAuthClient(config) | /client | Create web auth client (cookie-based) | | createNativeAuthClient(config) | /client | Create native/mobile auth client (Bearer token) | | createAuthContext(req) | . | Extract auth context from request | | getUserPermissions(userId) | . | Fetch all user permissions | | hasPermission(userId, ...perms) | . | Check user has all permissions | | requirePermission(userId, ...perms) | . | Guard — throws if permission missing | | requirePlan(userId, ...plans) | . | Guard — throws if plan mismatch | | requireFeature(userId, feature) | . | Guard — throws if feature unavailable | | checkLimit(userId, resource, count) | . | Check usage limit (non-throwing) | | generateApiKey(prefix?) | . | Generate API key + hash + prefix | | hashApiKey(key) | . | SHA-256 hash an API key | | validateApiKey(key) | . | Validate key against DB | | checkApiKeyScope(required, granted) | . | Check scope permission | | getSessionFromCookie(cookie, secret) | /edge | Edge-compatible session parsing | | withNovaAuth(config) | /nextjs/middleware | Next.js edge middleware factory | | createAuthPages(config?) | /nextjs | Catch-all auth page route factory | | NovaAuthProvider | /react | Web auth context provider | | useAuth() | /react | Web auth state hook | | SignIn, SignUp, UserButton, UserProfile | /react | Pre-built auth components | | SignedIn, SignedOut, ProtectedRoute | /react | Conditional rendering helpers | | NovaAuthProvider | /native | Mobile auth context provider | | useNovaAuth() | /native | Mobile auth state hook | | SignInScreen, SignUpScreen | /native | Expo screen wrappers |