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

@authowl/core

v0.19.0

Published

Framework-agnostic client for AuthOwl, the multi-tenant auth SaaS.

Readme

@authowl/core

Complete SDK guide · Server Admin guide · Error handling

Framework-agnostic client for AuthOwl, the multi-tenant auth service. Validates publishable keys, enforces HTTPS off localhost, and exposes typed errors. Most apps use @authowl/react or @authowl/next instead of this directly.

pnpm add @authowl/core

Upgrade notes

2026-08-22 — organization member email is nullable

OrganizationMemberUser.email is string | null. It was widened from string in 0.16.0, a minor release, so servers can withhold internal placeholder addresses without breaking decoding. Do not assume every organization member's address is visible to the current caller.

Before using the field as a string, provide a fallback (const email = user.email ?? '';) or guard against null.

Framework-neutral session state

Core has no React dependency. It exposes a standard external store for custom framework bindings and headless clients:

const unsubscribe = authowl.sessionStore.subscribe(() => {
  const session = authowl.sessionStore.getSnapshot();
  renderSession(session);
});

const initial = authowl.sessionStore.getSnapshot();

React applications should use useSession() from @authowl/react, which binds this store with React's external-store API and remains safe during SSR.

Generated server-only Admin API client

The @authowl/core/server entrypoint accepts a secret key (sk_live_…) for server-side admin calls. It refuses to run in a browser. Never import it from client code.

import { createAdminClient } from '@authowl/core/server';

const admin = createAdminClient({
  secretKey: process.env.AUTHOWL_SECRET_KEY!,
  apiUrl: 'https://auth.yourdomain.com',
});

const users = await admin.listUsers({ query: { limit: 50 } });
const user = await admin.getUser({ path: { userId: 'user_123' } });
await admin.updateUser({
  path: { userId: user.id },
  body: { name: 'Mona' },
});

await admin.updateUserMetadata({
  path: { userId: user.id },
  body: {
    expected_version: user.metadata_version,
    public_metadata: { locale: 'ar' },
    private_metadata: { billingTier: 'pro' },
  },
});

Publishable keys (pk_test_… in development, pk_live_… in production) are safe to embed in client code; secret keys (sk_test_… / sk_live_…) are bearer credentials and must stay server-side.

The operation names, path/query/body inputs, and result types are generated from AuthOwl's versioned OpenAPI contract. Failed API responses throw AuthOwlAdminApiError, which exposes status, code, requestId, problem, and retryAfter. Network and response-contract failures throw AuthOwlAdminNetworkError with a stable kind (aborted, timeout, network, response_too_large, or invalid_response).

import { AuthOwlAdminApiError } from '@authowl/core/server';

try {
  await admin.getUser({ path: { userId: 'missing' } });
} catch (error) {
  if (error instanceof AuthOwlAdminApiError && error.code === 'NOT_FOUND') {
    // Cross-project and missing resources both intentionally appear as 404.
  }
}

See the full Admin API reference, the phone OTP and Akedly Shield guide, and the webhook signature guide. Webhook receivers import verifyWebhook from @authowl/core/server; it works in Node and worker Web Crypto runtimes.

Stateless backend token verification

Import verification from the server-only subpath. The derived form validates the publishable key and API origin, then derives the exact AuthOwl issuer, audience, and JWKS route:

import { verifyToken } from '@authowl/core/server';

const identity = await verifyToken(bearerToken, {
  publishableKey: process.env.AUTHOWL_PUBLISHABLE_KEY!,
  apiUrl: process.env.AUTHOWL_API_URL!,
});

A fully custom deployment may instead pass all three explicit values:

const identity = await verifyToken(bearerToken, {
  issuer: 'https://issuer.example.com/custom',
  jwksUri: 'https://keys.example.net/v1/jwks',
  audience: 'my-application',
});

Do not mix the two forms or provide only part of one form. URLs must be canonical absolute HTTPS URLs without credentials, query strings, fragments, or encoded paths. A pk_test_ key may use HTTP only on exact loopback development hosts (localhost, *.localhost, 127.0.0.1, or [::1]); pk_live_ always requires HTTPS.

Verification accepts only app-shaped ES256 public keys. JWKS requests refuse redirects, abort after five seconds, stream at most 64 KiB, and accept at most 64 unique keys. Failures throw TokenVerificationError with a stable typed code; authorization helpers has() and hasPermission() continue to fail closed for token failures while surfacing configuration failures.

Headless account and organization management

Use the AuthOwl-owned account and organization namespaces when you are building custom UI. Their public types do not depend on the underlying auth engine.

import { createAuthOwlClient, getPublicConfig, resolveConfig } from '@authowl/core';

const config = resolveConfig({ publishableKey, apiUrl });
const authowl = createAuthOwlClient(config);
const capabilities = await getPublicConfig(config);

await authowl.account.updateProfile({ name: 'Mona' });
const sessions = await authowl.account.listSessions();
const otherSession = sessions.data?.[0];
if (otherSession) {
  await authowl.account.revokeSession({ sessionId: otherSession.id });
}
const metadata = await authowl.account.getMetadata();
if (metadata.data) {
  await authowl.account.updateUnsafeMetadata({
    expectedVersion: metadata.data.metadataVersion,
    unsafeMetadata: { onboarding: { step: 2 } },
  });
}

if (capabilities.organizations) {
  const organizations = await authowl.organization.list();
  const firstOrganization = organizations.data?.[0];
  if (firstOrganization) {
    await authowl.organization.setActive({ organizationId: firstOrganization.id });
  }
}

if (capabilities.userModel?.accountDeletion ?? capabilities.accountDeletion) {
  await authowl.account.delete();
}

The additive authentication, emailVerification, userModel, and mfa objects distinguish sign-in capability from account or credential creation. For example, a custom UI may call authowl.signIn.username(...) only when capabilities.authentication?.username.signIn is true, and may offer passkey registration only when capabilities.authentication?.passkey.add is true.

Sensitive mutations can return SESSION_NOT_FRESH with HTTP 403. Ask the user to sign in again and retry the action. Organization ownership conflicts return ORGANIZATION_LAST_OWNER. Disabled and cross-project resources return 404. Public metadata is server-authored. Unsafe metadata is end-user-owned and must be treated as untrusted. Private metadata has no browser SDK surface. Durable browser session tokens stay in HttpOnly cookies and never appear in @authowl/react's useSession(), action results, or listSessions(). Core exposes only the framework-neutral client.sessionStore. Session management uses stable session ids. This is distinct from getToken(), which intentionally mints a short-lived backend JWT and caches it in memory only.

Protected public-auth actions

When broad bot protection is enabled, obtain a fresh Turnstile token with the endpoint's exact action and pass it through authChallengeToken. The SDK sends the token only in x-authowl-turnstile-token; it never adds it to the JSON body. Tokens are single-use, so mint a new token for every attempt, including retries.

await authowl.signIn.email(
  { email, password },
  { authChallengeToken: turnstileToken },
);

| Client action | Turnstile action | | --- | --- | | signUp.email | auth_signup | | signIn.email | auth_signin | | signIn.magicLink, emailOtp.sendVerificationOtp | auth_passwordless | | requestPasswordReset | auth_reset | | sendVerificationEmail | auth_verify_email |

Drop-in React components read the public site key and manage this lifecycle automatically. Headless clients must still render Turnstile and bind the exact action themselves.

Named backend JWTs

Create a named template in the AuthOwl dashboard, then mint it from the signed-in browser session:

const token = await authowl.getToken({ template: 'supabase' });
const freshToken = await authowl.getToken({
  template: 'supabase',
  forceRefresh: true,
});

Template names are normalized to lowercase. Tokens stay memory-only and are cached separately by environment, user, active organization, template, and server policy version. A forced refresh bypasses only the selected template. Plain getToken() keeps the original unnamed-token contract.

See the full integration guide in the AuthOwl app repo (INTEGRATION.md).

License

MIT