v0.1Open source, MIT licensed

The front door for all your apps.

Ostiary is a self-hosted, open-source alternative to Auth0. One sign-in for every app you ship, with OpenID Connect, passkeys, two-factor, enterprise SSO and SCIM, and an admin console. Your users stay in your own Postgres.

git clone https://github.com/florianamette/ostiary
demo.ostiary.dev/login
The Ostiary sign-in screen: a dark brand panel with a brass doorway, and the sign-in form with email, password and passkey options.

Speaks the standards

  • OpenID Connect
  • OAuth 2.1
  • PKCE
  • WebAuthn
  • TOTP
  • JWT · JWKS
  • DPoP
  • Device flow
  • Dynamic registration
  • Client credentials
  • SAML 2.0
  • SCIM 2.0
  • Standard Webhooks

Everything behind the door

The identity stack, without the invoice.

The building blocks you would rent from a hosted platform, as a Next.js app you deploy and own. No per-user pricing, no black box.

OpenID Connect provider

A complete OAuth 2.1 and OIDC server: discovery, PKCE, consent, refresh tokens, UserInfo, introspection and JWKS. Anything that speaks OIDC signs in with Ostiary.

GET/.well-known/openid-configuration200
issuerhttps://auth.example.com/api/auth
authorization_endpoint…/oauth2/authorize
token_endpoint…/oauth2/token
jwks_uri…/jwks
grant_types_supportedauthorization_code, refresh_token, client_credentials

Passkeys

Passwordless sign-in with WebAuthn, alongside email and password, one-time email codes, usernames and social sign-in.

Sign in with a passkey

Face, fingerprint or security key

Two-factor authentication

Authenticator apps and backup codes, required for admins, plus an optional captcha (Turnstile, hCaptcha, reCAPTCHA) on sign-up and sign-in.

Enter the code from your app

48190|

Or use a backup code

Enterprise SSO

Let companies sign in with their own SAML 2.0 or OIDC identity provider (Okta, Entra ID, Google Workspace…), once they prove the domain with a DNS record.

  • acme.comSAMLVerified
  • globex.ioOIDCVerified
  • initech.devSAMLPending DNS

SCIM provisioning

Okta and Entra ID create, update and deactivate members of an organization. Leavers lose access at once.

  • Oktaada@acme.comcreated
  • Oktagrace@acme.comupdated
  • Entra IDalan@globex.iodeactivated

Admin console

Search users, change roles, ban, revoke sessions and impersonate. Manage OAuth clients, organizations and SSO providers, with an audit log of every admin action.

UserRoleStatusSeen
ada@acme.comadminActive2m ago
grace@globex.iouserActive1h ago
mallory@evil.testuserBanned3d ago

Audit log

  • user.banmallory@evil.test
  • oauth_client.createBilling app
  • sso_provider.verify_domainacme.com

Organizations

Teams with members, roles and email invitations, ready for B2B apps.

  • ALAda L.Owner
  • GHGrace H.Admin
  • ATAlan T.Member

20 languages

Every screen and email translated, right-to-left included, in light and dark themes.

  • English
  • Français
  • Deutsch
  • Español
  • 日本語
  • 한국어
  • العربية
  • हिन्दी
  • Português
  • Polski
  • Türkçe
  • Svenska
  • +8 more

Tokens for your APIs

Register your APIs and their scopes in the console. Choose which apps may call each one, token lifetimes, custom claims and DPoP-bound tokens.

// access token claims

aud https://api.example.com

scope orders:read orders:write

role admin

Device sign-in

CLIs, desktop apps and TVs show a short code; people approve it in the browser where they are already signed in.

$ acme login

Open auth.example.com/device

and enter WDJB-MJHT

✓ Signed in as ada@acme.com

Ready for AI agents

MCP clients and agents register themselves with Dynamic Client Registration or a client metadata document, when you turn it on. They stay limited to the scopes you allow, and people always see a consent screen.

POST/oauth2/register201

client_name "Research agent"

redirect_uris ["http://127.0.0.1:33418/callback"]

token_endpoint_auth_method "none"

Several accounts

Stay signed in to work and personal accounts at once, and pick which one an app gets.

  • ALada@acme.comActive
  • ALada@personal.devSwitch

36 social sign-in providers

Google, Apple, Microsoft, GitHub and 32 more, each with its own logo on the sign-in and sign-up screens. Turn them on from the console, no redeploy, with Google One Tap. People link several to one account.

  • Google
  • Apple
  • Microsoft
  • GitHub
  • GitLab
  • Discord
  • Slack
  • LinkedIn
  • X
  • Twitch
  • Notion
  • Spotify

+24 more, from Figma and Zoom to Salesforce and Cognito

Webhooks

Your apps hear when users sign up, change, get banned or join an organization. Signed, retried, with a delivery log.

  • user.created200
  • organization.member.added200
  • user.banned503 · retry in 5m

API keys

People and organizations create long-lived keys for scripts, limited to one of your APIs and its scopes. Your API checks them in one call.

POST/api-key/verify200

valid true

scopes ["orders:read"]

Signing key rotation

Rotate the keys that sign tokens on a schedule or with one click. Old keys keep verifying for a grace period.

  • kid 9f3c…Signing
  • kid 41ab…Verifying · 30 days

Rate limits that hold

Sign-in, codes and emails are limited per address in Postgres, so the limits hold on serverless too.

POST /sign-in/email 429

Retry-After 42

Try again in 42 seconds.

Branding per app

Each app you register gets its logo, colors and headline on the sign-in screens. Your own mark always stays, so people know where they type their password.

A

Sign in to continue to

Acme Analytics

Continue

Export and deletion

People download everything you hold about them as JSON, or delete their account after an emailed confirmation. GDPR access, portability and erasure, built in.

my-data-2026-10-09.json

sessions, passkeys, apps included

secrets, tokens never

Connect an app

A few lines to sign in.

Ostiary is a standard OpenID Connect provider, so there is no SDK to learn. Use the OIDC library you already have.

  1. 01

    Register your app

    Create an OAuth client in the admin console and copy its ID and secret.

  2. 02

    Point it at Ostiary

    Give your OIDC library the issuer URL. Discovery handles the rest.

  3. 03

    Ship

    Users sign in once and move between your apps without a second password.

  • Next.js
  • Remix
  • SvelteKit
  • iOS & Android
  • CLIs
  • Your APIs
Ostiaryyour Postgres
auth.ts
Auth.js
import NextAuth from "next-auth";

export const { handlers, auth, signIn, signOut } = NextAuth({
  providers: [
    {
      id: "ostiary",
      name: "Ostiary",
      type: "oidc",
      issuer: "https://auth.example.com/api/auth",
      clientId: process.env.OSTIARY_CLIENT_ID,
      clientSecret: process.env.OSTIARY_CLIENT_SECRET,
    },
  ],
});

Works the same with Better Auth's generic OAuth plugin, openid-client or AppAuth on mobile.

How it compares

Own it, or rent it.

An honest table. Ostiary fits when you want to own your identity layer. If you need a managed service with compliance certifications and an SLA, a hosted platform is the better choice.

Capability OstiaryAuth0
Where your users liveYour PostgresThe vendor's cloud
PricingYour hosting billPer monthly active user
Source codeYours, MITClosed
OIDC and OAuth 2.1 provider
Passkeys, 36 social providers, organizations
Two-factor, email codes, captcha
Device flow and dynamic client registration
Enterprise SSOOIDC and SAMLOIDC and SAML
SCIM provisioning, breached-password detection
Webhooks, API keys, signing key rotation
Branding per app, data export and account deletion
Admin console and audit log
Compliance certifications and SLA

Deploy

Live in a few minutes.

Ostiary is a Vercel template. Bring a Resend account for email; everything else is provisioned for you.

Deploy to Vercel
  1. 01

    Deploy

    One click creates the project on Vercel with a Neon Postgres database.

  2. 02

    Configure

    Add a secret, your admin email and a Resend key. Migrations run during the build.

  3. 03

    Sign up

    Create your account. Your email becomes the first admin.

Or run it anywhere.

It's a pnpm monorepo of two Next.js apps and a shared core. Any Node host and any Postgres will do.

terminal
pnpm install
cp apps/auth/.env.example apps/auth/.env.local
pnpm db:migrate
pnpm dev:auth   # http://localhost:3000

Hold the keys.

Your own identity provider, deployed in minutes. MIT licensed, free to use, yours to change.