Run it locally¶
The whole provider, on your machine, over a local D1 database. Same code as https://auth.omxus.com. Checked on 30 Oct 2026 with Wrangler 4.152 and Node 26: all migrations applied, discovery and JWKS answered, a client registered, the runtime smoke test passed 4 of 4.
You only need this to work on the provider itself. To add sign-in to your site, register it on auth.omxus.com instead.
1. Install¶
2. Make .dev.vars¶
wrangler dev reads local secrets and settings from .dev.vars in the repo
root. It is gitignored. Mint fresh secrets:
That prints three wrangler secret put lines, each followed by its value. It
is not a .dev.vars file: copy the values into one by hand, like this.
OIDC_SIGNING_JWK={"kty":"EC","crv":"P-256",...}
PAIRWISE_SALT=3f9c...
ISSUER=http://localhost:8787
RP_ID=localhost
INSECURE_COOKIES=1
| Setting | Why |
|---|---|
OIDC_SIGNING_JWK |
Signs every ID token. A local key, never the production one. |
PAIRWISE_SALT |
Behind every sub. Change it and every sub changes. |
ISSUER |
wrangler.toml sets https://auth.omxus.com. Locally it must be the address you run on, port included, or every redirect, token and discovery answer points at production. |
RP_ID |
Overrides auth.omxus.com from wrangler.toml. |
INSECURE_COOKIES=1 |
Session cookies are Secure by default and never arrive over plain http. |
Optional: RECOVERY_JWK (the third printed value) turns on the email and
password door; without it /email/* answers 404. ACCOUNTS_LOG_CODES=1 prints
sign-up codes to the console when no email binding can deliver them. See
Email and texts.
3. Make the database¶
This applies 20 migration files in order to a local D1 in .wrangler/state/
and ends with local D1 ready: 41 tables. It is safe to run twice; it skips
any column already there. To start clean, delete .wrangler/state/ and run it
again.
4. Start it¶
Check it:
curl -s localhost:8787/.well-known/openid-configuration | head
curl -s -o /dev/null -w '%{http_code}\n' localhost:8787/oidc/jwks # 200
The issuer in the first answer must read http://localhost:8787. If it reads
https://auth.omxus.com, ISSUER is missing from .dev.vars.
The designed sign-in page comes from frontend/dist. Build it once with
cd frontend && npm run build; without it the plain page is served.
5. Register a client¶
The same call as production, against your own provider:
curl -s -X POST localhost:8787/oidc/register \
-H 'content-type: application/json' \
-d '{"client_name":"My Site",
"redirect_uris":["http://localhost:3000/callback"],
"token_endpoint_auth_method":"none"}'
The answer holds your client_id. The form at
http://localhost:8787/developers does the same. Fields and rules:
Registering a site.
The smoke test¶
worker/smoke.test.mjs signs in against a running Worker, takes a code,
verifies the ID token against the Worker's JWKS and checks sub is pairwise.
It is the one test that sees the Workers runtime, so it is not in npm test.
It expects the provider on port 8789 and a client called smoke-test, so
run a second copy for it:
npx wrangler dev --port 8789 --ip 127.0.0.1 \
--var ISSUER:http://localhost:8789 --var INSECURE_COOKIES:1
npx wrangler d1 execute omxus-auth-v2 --local --command \
"INSERT OR REPLACE INTO oidc_clients
(client_id, name, redirect_uris, secret_hash, sector_identifier)
VALUES ('smoke-test','Smoke Test','[\"https://example.test/cb\"]',NULL,NULL)"
npm run worker:smoke # 4/4 passed
--var overrides .dev.vars for that one run, so both copies share the
signing key and the database.
When it will not start¶
Address already in use (127.0.0.1:8787): something holds the port. Wrangler
dev servers outlive the terminal that started them:
Pick another port only if you change ISSUER to match.
Deploying your own¶
Running a provider covers what a real deployment
needs. In short: create your own D1 and put its id, your account and your
route in wrangler.toml; set ISSUER there to your https address; run
npm run worker:db:remote; wrangler secret put each printed secret (new
ones, not the local ones); cd frontend && npm run build; then
npm run worker:deploy.
Costs¶
Free tier covers it: Workers 100,000 requests a day, D1 5 million row reads and 100,000 writes a day, static assets not billed. Roughly 30,000 sign-ins a day before anything costs money.