ScriptsMay 11, 2026·4 min read

OpenAuth — Universal Auth Server You Can Self-Host

Dax Raad's team's centralized auth server you self-host. Multi-tenant, OAuth/password/SAML/passkey. Auth0/Clerk replacement with full control.

Agent ready

Safe staging for this asset

This asset is staged first. The copied prompt tells the agent to inspect the staged files and ask before activating scripts, MCP config, or global config.

Stage only · 29/100Policy: stage
Agent surface
Any MCP/CLI agent
Kind
Skill
Install
Stage only
Trust
Trust: Community
Entrypoint
Asset
Safe staging command
npx -y tokrepo@latest install 4ef9462d-c757-48ec-93c1-db0c2835dc0c --target codex

Stages files first; activation requires review of the staged README and plan.

Intro

OpenAuth is a centralized auth server from Dax Raad's team (SST / Toolbeam) — self-host one OpenAuth server that issues OAuth-compatible tokens to all your apps, no matter what auth method (password, OAuth provider, SAML, passkey, magic link). Standards-based, multi-tenant, zero-vendor-lock-in alternative to Auth0/Clerk. Best for: side projects scaling to multiple apps, teams burned by Auth0 pricing tiers, anyone wanting full control over the user database. Works with: any web framework — TS, Python, Go, Rust, PHP. Setup time: 15 minutes.


Server (TypeScript example)

import { issuer } from "@openauthjs/openauth";
import { PasswordProvider } from "@openauthjs/openauth/provider/password";
import { GithubProvider } from "@openauthjs/openauth/provider/github";
import { CodeUI } from "@openauthjs/openauth/ui/code";
import { PasswordUI } from "@openauthjs/openauth/ui/password";

const auth = issuer({
  storage: { type: "dynamo", table: "openauth" },
  providers: {
    password: PasswordProvider(PasswordUI({ /* email + password UI */ })),
    github: GithubProvider({
      clientID: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
      scopes: ["user:email"],
    }),
  },
  success: async (ctx, value) => {
    return ctx.subject("user", {
      id: value.email || value.clientID + ":" + value.id,
    });
  },
});

export const handler = auth.handler;   // mount on AWS Lambda / Vercel Functions

Client app (any framework)

import { createClient } from "@openauthjs/openauth/client";

const client = createClient({
  clientID: "my-app",
  issuer: "https://auth.example.com",
});

// Redirect to login
window.location.href = await client.authorize(
  "https://my-app.com/callback",
  "code"
);

// On callback
const tokens = await client.exchange(code, "https://my-app.com/callback");
// tokens.access, tokens.refresh — standard OAuth, use anywhere

Why OpenAuth vs Auth0/Clerk

Need OpenAuth Auth0 Clerk
Self-host Yes No (Private Cloud add-on $$$) No
Pricing Free (your infra) $-$$$$ per MAU Per MAU
Multi-tenant Built-in Yes Yes
Standards-based OAuth/OIDC native OAuth/OIDC Proprietary + OIDC
Storage Postgres / DynamoDB / Cloudflare KV Theirs Theirs
Lock-in None (your DB) Vendor Vendor

Production checklist

  • HTTPS only (issuer redirects break on HTTP)
  • Rotate signing keys every 90 days (auth.rotate())
  • Set short-lived access tokens (15 min) + long refresh (30 days)
  • Use Cloudflare KV or DynamoDB for global edge latency

FAQ

Q: Is it production-ready? A: Yes — Toolbeam runs it in production, several Anthropic-adjacent projects use it. Still v1.x so breaking changes possible. Pin a version and test upgrades.

Q: Storage options? A: Built-in adapters for DynamoDB (recommended for AWS-native), Cloudflare KV (edge-friendly), Postgres (self-host shops), and in-memory for tests. Custom adapter is a ~50-line file.

Q: How does it compare to Lucia / NextAuth? A: Lucia/NextAuth are libraries embedded in your app. OpenAuth is a separate centralized server — preferred when you have 3+ apps sharing users. For one app, NextAuth is simpler. For an org with many apps, OpenAuth is the cleaner architecture.


Quick Use

  1. npm install @openauthjs/openauth
  2. Author issuer({providers, success}) and deploy to Lambda / Vercel Functions
  3. Client app uses createClient().authorize(...) for OAuth flow

Intro

OpenAuth is a centralized auth server from Dax Raad's team (SST / Toolbeam) — self-host one OpenAuth server that issues OAuth-compatible tokens to all your apps, no matter what auth method (password, OAuth provider, SAML, passkey, magic link). Standards-based, multi-tenant, zero-vendor-lock-in alternative to Auth0/Clerk. Best for: side projects scaling to multiple apps, teams burned by Auth0 pricing tiers, anyone wanting full control over the user database. Works with: any web framework — TS, Python, Go, Rust, PHP. Setup time: 15 minutes.


Server (TypeScript example)

import { issuer } from "@openauthjs/openauth";
import { PasswordProvider } from "@openauthjs/openauth/provider/password";
import { GithubProvider } from "@openauthjs/openauth/provider/github";
import { CodeUI } from "@openauthjs/openauth/ui/code";
import { PasswordUI } from "@openauthjs/openauth/ui/password";

const auth = issuer({
  storage: { type: "dynamo", table: "openauth" },
  providers: {
    password: PasswordProvider(PasswordUI({ /* email + password UI */ })),
    github: GithubProvider({
      clientID: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
      scopes: ["user:email"],
    }),
  },
  success: async (ctx, value) => {
    return ctx.subject("user", {
      id: value.email || value.clientID + ":" + value.id,
    });
  },
});

export const handler = auth.handler;   // mount on AWS Lambda / Vercel Functions

Client app (any framework)

import { createClient } from "@openauthjs/openauth/client";

const client = createClient({
  clientID: "my-app",
  issuer: "https://auth.example.com",
});

// Redirect to login
window.location.href = await client.authorize(
  "https://my-app.com/callback",
  "code"
);

// On callback
const tokens = await client.exchange(code, "https://my-app.com/callback");
// tokens.access, tokens.refresh — standard OAuth, use anywhere

Why OpenAuth vs Auth0/Clerk

Need OpenAuth Auth0 Clerk
Self-host Yes No (Private Cloud add-on $$$) No
Pricing Free (your infra) $-$$$$ per MAU Per MAU
Multi-tenant Built-in Yes Yes
Standards-based OAuth/OIDC native OAuth/OIDC Proprietary + OIDC
Storage Postgres / DynamoDB / Cloudflare KV Theirs Theirs
Lock-in None (your DB) Vendor Vendor

Production checklist

  • HTTPS only (issuer redirects break on HTTP)
  • Rotate signing keys every 90 days (auth.rotate())
  • Set short-lived access tokens (15 min) + long refresh (30 days)
  • Use Cloudflare KV or DynamoDB for global edge latency

FAQ

Q: Is it production-ready? A: Yes — Toolbeam runs it in production, several Anthropic-adjacent projects use it. Still v1.x so breaking changes possible. Pin a version and test upgrades.

Q: Storage options? A: Built-in adapters for DynamoDB (recommended for AWS-native), Cloudflare KV (edge-friendly), Postgres (self-host shops), and in-memory for tests. Custom adapter is a ~50-line file.

Q: How does it compare to Lucia / NextAuth? A: Lucia/NextAuth are libraries embedded in your app. OpenAuth is a separate centralized server — preferred when you have 3+ apps sharing users. For one app, NextAuth is simpler. For an org with many apps, OpenAuth is the cleaner architecture.


Source & Thanks

Built by Toolbeam (Dax Raad's team). Licensed under MIT.

toolbeam/openauth — ⭐ 2,800+

🙏

Source & Thanks

Built by Toolbeam (Dax Raad's team). Licensed under MIT.

toolbeam/openauth — ⭐ 2,800+

Discussion

Sign in to join the discussion.
No comments yet. Be the first to share your thoughts.

Related Assets