Off the hot path
Access tokens are EdDSA JWTs your backend verifies in-process against a cached JWKS. A request with a valid token never waits on authbase.
In development · self-hosted · Apache-2.0
One binary and one PostgreSQL hold the users of every product you build. Your backend signs them up and logs them in with an API key, then verifies their tokens locally. authbase is never on your hot path.
Early preview. authbase is in active development and already runs in production for its author. The source code and packages are not public yet; this site introduces the project and documents how it works ahead of the first public release.
import { Authbase } from "@authbase/node";
import { requireAuth } from "@authbase/node/express";
const authbase = new Authbase({
url: process.env.AUTHBASE_URL!,
apiKey: process.env.AUTHBASE_API_KEY!,
});
app.post("/login", async (req, res) => {
const tokens = await authbase.auth.login({
identifier: req.body.email,
password: req.body.password,
client_ip: req.ip,
});
res.json(tokens);
});
// Verified locally against the app's JWKS
app.get("/me", requireAuth(authbase), (req, res) => {
res.json({ id: req.auth!.sub, roles: req.auth!.roles });
});val authbase = Authbase(
url = System.getenv("AUTHBASE_URL"),
apiKey = System.getenv("AUTHBASE_API_KEY"),
)
install(Authentication) { authbase { client(authbase) } }
routing {
post("/login") {
val c = call.receive<Credentials>()
call.respond(authbase.auth.login(
LoginRequest(identifier = c.email, password = c.password, clientIp = call.request.origin.remoteHost)
))
}
// Verified locally against the app's JWKS
authenticate("authbase") {
get("/me") { call.respond(call.authbase!!.subject) }
}
}# Your backend logs a user in with the app's API key
curl https://auth.example.com/v1/auth/login \
-H "Authorization: Bearer $AUTHBASE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"identifier":"ada@example.com","password":"…","client_ip":"203.0.113.9"}'
# → { "access_token": "eyJ…", "refresh_token": "rt_…", "expires_in": 900, … }
# …and checks access tokens with any JWT library, against
curl https://auth.example.com/apps/cashmate/.well-known/jwks.jsonauthbase owns your users' credentials and issues their tokens. Your product keeps its own database and logic.
Access tokens are EdDSA JWTs your backend verifies in-process against a cached JWKS. A request with a valid token never waits on authbase.
Argon2id, the 100,000 most common leaked passwords refused, per-IP and per-key rate limits, lockout, refresh-token reuse detection and an audit log.
RFC 9068 access tokens, a JWKS and OIDC discovery document per app, RFC 9457 errors with stable codes, and an OpenAPI spec for all of it.
Each product is an app with its own users, keys, issuer and settings. One instance serves all of them; nothing leaks between apps.
Password reset, email verification and security notices, with hosted pages that work without JavaScript, or links to your own pages.
One binary, PostgreSQL 16+, one master key. A dashboard for apps, keys, users and the audit log; runbooks for backups, upgrades and key rotation.
SDKs for Node (Express, Hono, Next.js) and Kotlin/JVM (Ktor, Spring Boot). Go, Python and everything else: JSON over HTTP and a JWT library.
Point your agent at the docs and it gets plain markdown, the full API contract and the rules that keep an integration safe. With Claude, install the skills and ask it to add authbase to your app.
Docs for agents/llms.txtan index of every page, for agents/docs/*.mdeach page as plain markdown/openapi.yamlevery endpoint and error codeskillsClaude skills, with the public releaseThe quick start shows the whole flow: start authbase, create an app, and put an example backend on it.