Skip to content
Early preview. authbase is in active development. The source code and packages are not public yet; these docs describe how it works ahead of the first public release.

@authbase/node

authbase for Node backends (Node 20.19+, ESM): a typed client for the end-user API and offline access-token verification, with helpers for Express, Hono and Next.js. Not on npm yet (it will be at the public release): install it from a packed tarball.

Terminal window
cd sdk/typescript && npm ci && npm run build && npm pack # → authbase-node-0.1.0.tgz
cd your-app && npm install ../authbase/sdk/typescript/authbase-node-0.1.0.tgz

One per app, with the app’s API key from the environment (never in code):

import { Authbase, AuthbaseError } from "@authbase/node";
const authbase = new Authbase({ url: process.env.AUTHBASE_URL!, apiKey: process.env.AUTHBASE_API_KEY! });
await authbase.users.create({ email, password });
const tokens = await authbase.auth.login({ identifier: email, password, client_ip: req.ip });
const next = await authbase.auth.refresh({ refresh_token: tokens.refresh_token });
await authbase.auth.logout({ refresh_token: next.refresh_token });

Every method throws AuthbaseError on a non-2xx answer: status, code (branch on this), detail, requestId, errors (per field, for 422) and retryAfter (429/503). An unreachable server is code: "network_error".

Tokens are verified locally against the app’s JWKS: fetched once, cached for 5 minutes, refetched (at most once a second) when a token carries an unknown kid, so a signing-key rotation needs no restart. Only EdDSA, typ: at+jwt, the app’s issuer and the app id as aud are accepted.

const claims = await authbase.verifyAccessToken(token); // learns issuer and app id once from GET /v1/app

A service that only checks tokens needs no API key:

import { createVerifier } from "@authbase/node";
const verify = createVerifier({ issuer: "https://auth.example.com/apps/cashmate", appId: "01a0…" });

A bad token throws AuthbaseTokenError (token_expired, worth a refresh, or token_invalid). A JWKS that cannot be fetched throws something else: that is an outage, not the caller’s fault.

Each takes the client or { issuer, appId }, and optionally { roles } (all required). Missing or bad tokens get 401 with WWW-Authenticate: Bearer (RFC 6750), missing roles 403, an unreachable JWKS 503; bodies are problem+json.

// Express
import { requireAuth } from "@authbase/node/express";
app.get("/me", requireAuth(authbase), (req, res) => res.json({ id: req.auth!.sub }));
// Hono
import { requireAuth, type AuthVariables } from "@authbase/node/hono";
const app = new Hono<{ Variables: AuthVariables }>();
app.get("/me", requireAuth(authbase, { roles: ["admin"] }), (c) => c.json({ id: c.get("auth").sub }));
// Next.js route handler (app/api/me/route.ts)
import { withAuth } from "@authbase/node/next";
export const GET = withAuth(authbase, async (req, { auth }) => Response.json({ id: auth.sub }));

npm run check regenerates the client from api/openapi/openapi.yaml (and fails if the committed copy is stale), typechecks, tests and builds. AUTHBASE_TEST_URL=http://localhost:8080 npm test also runs the integration test against a real instance.