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

@simpleauthjs/core

v0.0.1

Published

JavaScript SDK for SimpleAuth

Readme

@simpleauthjs/core

A tiny JavaScript SDK for the SimpleAuth auth API (/api/external/auth/*).

Installation

npm install @simpleauthjs/core

60-second quickstart

import { createSimpleAuthClient } from "@simpleauthjs/core"

const auth = createSimpleAuthClient({
  apiKey: "sa_live_your_key",
})

await auth.register({
  email: "[email protected]",
  password: "password123",
  name: "Demo User",
})

await auth.login({ email: "[email protected]", password: "password123" })
console.log(await auth.me())
await auth.logout()

Client options

createSimpleAuthClient({
  apiKey: string,                  // required — sent in headers only (never in JSON body)
  baseUrl?: string,                // default: "https://simpleauth.net" (falls back to SIMPLEAUTH_BASE_URL env)
  apiKeyTransport?: "authorization" | "x-api-key", // default: "authorization"
  fetch?: typeof fetch,            // custom fetch implementation
  credentials?: "include" | ... , // default: "include"
  headers?: Record<string, string>,
  timeoutMs?: number,
  onError?: (error: SimpleAuthError) => void,
  onRequest?: (event) => void,      // request tracing hook
  onResponse?: (event) => void,     // response tracing hook
  debug?: boolean,                  // debug logging in console
})

Base URL resolution

The baseUrl is resolved in this order:

  1. Explicit baseUrl option passed to the constructor.
  2. process.env.SIMPLEAUTH_BASE_URL environment variable (optional; use when pointing at a local SimpleAuth server, for example http://localhost:3000).
  3. "https://simpleauth.net" (default for the hosted API).

API key in requests

The app API key is sent using:

  • apiKeyTransport: "authorization" (default): Authorization: Bearer <apiKey>
  • apiKeyTransport: "x-api-key": X-API-Key: <apiKey>

The server accepts either header. Credentials and user payloads (email, password, etc.) stay in the JSON body; the key is never duplicated there.

Apps have two key types in the dashboard: a public key (sa_live_…) for clients and this package's default client, and a secret key (sa_secret_…) for trusted backends. User provisioning (createUser) lives under @simpleauthjs/core/server and uses the secret key (see below).

Example with options

const auth = createSimpleAuthClient({
  apiKey: "sa_live_your_key",
  timeoutMs: 10_000,
  onError: (error) => {
    console.error("SDK error:", error.status, error.code, error.message)
  },
  onRequest: (event) => {
    console.log("request", event)
  },
  onResponse: (event) => {
    console.log("response", event.status, `${event.durationMs}ms`)
  },
})

DX notes

  • SDK validates required input fields and throws early (email, password, token, etc.) for faster feedback.
  • Sensitive values are redacted from debug/request traces (apiKey, password, token).
  • If your frontend runs on https:// and baseUrl uses http://, SDK prints a warning.

Exposed methods

Core auth

  • register({ email, password, name? })
  • login({ email, password })
  • me()
  • logout()
  • deleteAccount({ password }) — requires session cookies; confirms password then deletes the user (see below).
  • isAuthenticated()

Recovery and verification

  • forgotPassword({ email })
  • resetPassword({ token, password }) — sends the app API key; the reset token must belong to that app.
  • sendVerificationEmail({ email }) — also available as resendVerification (alias)
  • verifyEmail({ token }) — sends the app API key; the verification token must belong to that app.

All methods return promises.


Method examples

Register

const result = await auth.register({
  email: "[email protected]",
  password: "password123",
  name: "Demo",
})

console.log(result.user)

Create user (server-only, secret key)

Import from @simpleauthjs/core/server (not @simpleauthjs/core). This entry is for Node, Edge, and other server runtimes only; it throws if loaded in a browser bundle.

It uses the same base URL resolution as the client (baseUrlSIMPLEAUTH_BASE_URLhttps://simpleauth.net). The secret API key (sa_secret_…) comes from SIMPLEAUTH_SECRET_KEY / secretKey and is required for admin methods below. You can omit the secret key if you only use currentUser() (session cookies).

Same payload and { user } response as register; createUser calls POST /api/external/auth/admin/users and emits the same user.registered webhook server-side.

import { createServerSimpleAuthClient } from "@simpleauthjs/core/server"

const adminAuth = createServerSimpleAuthClient()
// or: createServerSimpleAuthClient({ secretKey }) to override env

await adminAuth.createUser({
  email: "[email protected]",
  password: "temporarySecret123",
  name: "New User",
})

Other admin HTTP routes (secret key only):

| Method | Path | SDK | |--------|------|-----| | POST | /api/external/auth/admin/users/:id/ban body { durationMinutes } | banUser(externalUserId, { durationMinutes }) | | POST | /api/external/auth/admin/users/:id/unban | unbanUser(externalUserId) | | GET | /api/external/auth/admin/users/:id | getUserById(externalUserId) — returns { user } with bannedUntil | | DELETE | /api/external/auth/admin/users/:id | deleteUserById(externalUserId) — permanent delete; user.deleted webhook | | GET | /api/external/auth/admin/users/:id/sessions | listUserSessions(externalUserId) — metadata only (no session tokens) | | DELETE | /api/external/auth/admin/users/:id/sessions/:sessionId | deleteUserSession(externalUserId, sessionId) — revoke that login | | POST | /api/external/auth/admin/users/:id/revoke-all-sessions | revokeAllUserSessions(externalUserId){ success, revokedCount } |

await adminAuth.banUser("ext_user_id", { durationMinutes: 60 })
await adminAuth.unbanUser("ext_user_id")
const { user } = await adminAuth.getUserById("ext_user_id")
const { sessions } = await adminAuth.listUserSessions("ext_user_id")
await adminAuth.deleteUserSession("ext_user_id", sessions[0].id)
await adminAuth.revokeAllUserSessions("ext_user_id")
await adminAuth.deleteUserById("ext_user_id")

Current signed-in user (currentUser)

For server-rendered pages and API routes, call currentUser(requestLike) to load the same user as the browser me endpoint. It performs GET /api/external/auth/me and forwards session cookies from the incoming request (it does not send the secret API key). Pass the Web Request from your handler, or { cookie: "..." }, or { headers } (e.g. Next.js headers()).

import { createServerSimpleAuthClient, SimpleAuthError } from "@simpleauthjs/core/server"

const auth = createServerSimpleAuthClient()

export async function GET(request) {
  try {
    const { user } = await auth.currentUser(request)
    return Response.json(user)
  } catch (e) {
    if (e instanceof SimpleAuthError && e.status === 401) {
      return new Response("Unauthorized", { status: 401 })
    }
    throw e
  }
}

Cookies sa_ext_session and sa_ext_app must be present on the request (set after login when the client talks to your app with credentials).

Login

await auth.login({
  email: "[email protected]",
  password: "password123",
})

If the account is suspended (banned), the server responds with 403 and an error message such as "Account is suspended". Your UI should treat this like a failed login.

Current user

const me = await auth.me()
console.log(me.user)

Logout

await auth.logout()

Delete account

Requires a logged-in session (login first) and the user's current password. The app API key is not sent on this request (only session cookies). On success the server clears auth cookies and removes the user; your app should stop using this client for that user.

await auth.deleteAccount({ password: "currentPassword123" })

Forgot/reset password

forgotPassword and resetPassword both send the app API key in headers. The server resolves the app from the key; the reset link token must have been issued for that same app, and the user must still exist.

await auth.forgotPassword({ email: "[email protected]" })

await auth.resetPassword({
  token: "password-reset-token",
  password: "newPassword123",
})

Email verification

sendVerificationEmail sends the app API key. verifyEmail also sends the app API key; the token in the link must be for that same app.

await auth.sendVerificationEmail({ email: "[email protected]" })
await auth.verifyEmail({ token: "email-verification-token" })

Error handling

SDK methods throw SimpleAuthError.

import { createSimpleAuthClient, SimpleAuthError } from "@simpleauthjs/core"

try {
  await auth.login({ email: "[email protected]", password: "wrong" })
} catch (error) {
  if (error instanceof SimpleAuthError) {
    console.error(error.status, error.code, error.message)
    console.error(error.details)
  }
}

Browser cookie requirements

SimpleAuth external sessions use HttpOnly cookies. In browser apps:

  1. Keep credentials: "include" (SDK default).
  2. Ensure backend CORS allows credentials for your frontend origin.
  3. Ensure same-site/domain settings match your deployment topology.

Migration note

If you were using legacy SDK routes under /api/saas/auth/*, migrate to this SDK version which targets /api/external/auth/*.

If you previously sent the app API key in the JSON body yourself (without this SDK), switch to Authorization: Bearer or X-API-Key on the server; this SDK already uses headers only.


Troubleshooting

401 Unauthorized on me()

  • Check that login() succeeded.
  • Confirm browser is sending cookies (credentials: include).
  • Confirm server CORS and cookie config.

Invalid API key

  • Ensure you are using the current active app key (rotating a key revokes prior key).

Request timeout

  • Increase timeoutMs when creating the client.

Integration fixture (Node script)

A runnable fixture is available at:

packages/simpleauth-js/examples/node-script/demo.mjs

Run it with:

SIMPLEAUTH_API_KEY=sa_live_your_key \
node packages/simpleauth-js/examples/node-script/demo.mjs

For createServerSimpleAuthClient, set SIMPLEAUTH_SECRET_KEY in the environment instead of SIMPLEAUTH_API_KEY.


Local SDK tests

cd packages/simpleauth-js
npm test