Auth
Sign-in for your app — social providers and one-time codes — in one command.
AI/LLM: this page is available in plain markdown at /docs/resources/authlocker.md
npx extraorbital add authlocker✓ Provisioned authlocker/default
✓ Wrote 3 variables to .env
AUTHLOCKER_CLIENT_ID, AUTHLOCKER_CLIENT_SECRET, AUTHLOCKER_ISSUERA project that mentions AUTHLOCKER_CLIENT_ID gets this from
extraorbital provision without naming it.
What it writes
| Variable | Example |
|---|---|
AUTHLOCKER_CLIENT_ID | al_2mJyR1oqIl9P2DJCYg8XEg |
AUTHLOCKER_CLIENT_SECRET | als_9c4e… |
AUTHLOCKER_ISSUER | https://authlocker.dev |
Two ways in, from one credential pair. Social sign-in is a standards-compliant OAuth 2.1 / OIDC flow, so any OIDC library speaks it from the discovery document and no vendor SDK is required. Email and SMS one-time codes are a pair of server-to-server calls — the service generates every code, counts every attempt and owns the lockout, so none of that lives in your app.
You do not register a callback URL. The first one your app actually uses is pinned to the client, per provider, and every later request must match it exactly. Localhost always works and pins nothing, so development never spends the pin on a URL no user will visit.
Options
npx extraorbital add authlocker [--slug <name>]| Flag | Default | Description |
|---|---|---|
--slug | default | A second, fully separate client |
One client per app, not per environment. The subject in the token is pairwise — derived per client — so two clients see the same person as two different users.
Prototype allowance
Fair use on the Prototype plan. Social sign-in and email codes are included; SMS draws on a shared daily ceiling, which is enough to build against and deliberately not enough to be worth abusing. Past it, SMS is passed through at cost — from $0.011 a message, varying by destination — on a paid plan.
Usage is metered per login, per code sent and per code approved, so
extraorbital ledger shows what was actually used rather than a flat zero.
Use it
One route handler holds the secret, because the verify API takes a client secret and answers no CORS headers — a browser can never call it:
import { createAuthLockerHandler } from "@authlocker/next";
export const { GET, POST } = createAuthLockerHandler({
capabilities: ["socials.google", "socials.github", "otp.email"],
async onUserVerified(request, user) {
// user: { method, provider, sub, email, emailVerified, name, picture }
// Write your session cookie here — this response is the one that carries it.
},
});And the client half needs no configuration, because both halves read the same path constant:
import { AuthLockerNextProvider } from "@authlocker/next/client";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return <AuthLockerNextProvider>{children}</AuthLockerNextProvider>;
}Prebuilt sign-in components install with npx shadcn@latest add, and
authlocker.dev/components generates both
the React and the server code for whatever arrangement you pick.