Shared Cloudflare Worker for id.wavey.ai.
This service is the single Wavey-owned identity front door for Bitneedle,
Infidelity, and Wavey apps. The active implementation is the generic Rust
Zeroth Worker in ../zeroth; this repo owns deployment configuration,
registered clients, provider credentials, and Wavey-specific Apple association
data.
Login can remain disabled in relying apps while this service is deployed and configured.
The default npm run dev, npm run deploy:dry-run, and npm run deploy
commands use wrangler.zeroth.jsonc and deploy the generic Zeroth Worker as
id.wavey.ai without copying auth implementation code into this repo.
The zeroth:* Cloudflare scripts run through scripts/zeroth-cloudflare.mjs.
By default it reads the Wavey/Bitneedle global API key from ../.cloudflare-token,
sets CLOUDFLARE_EMAIL=jamie@wavey.ai, and unsets any stale
CLOUDFLARE_API_TOKEN before invoking Wrangler. Set CLOUDFLARE_API_KEY_PATH
or CLOUDFLARE_EMAIL to override those defaults, or set
ZEROTH_CLOUDFLARE_AUTH=oauth to intentionally use the saved Wrangler login.
This keeps deployment on the credential path that can read and edit Workers
Scripts for account c57bb20727aa3564966d2bb693abddce.
npm install
npm run deploy:dry-run
npm run zeroth:deploy:preflight:local
npm run zeroth:verify:localBefore the first deploy, create a D1 database and replace
database_id in wrangler.zeroth.jsonc:
npx wrangler d1 create wavey-id-zerothApply the generic schema and Wavey-owned registered clients:
npm run zeroth:d1:initThe direct D1 helper asks zeroth-cli for the generic schema exported by
zeroth-storage, repairs compatibility columns for older test databases,
records the generic init migration in zeroth_schema_migrations, and then
seeds Wavey-owned clients. Inspect the generic SQL with:
npm run zeroth:schemaBootstrap Zeroth signing and admin secrets before provider credentials are available. The generated file is ignored by Git and should stay local:
mkdir -p .wrangler
npm run --silent zeroth:signing-key -- --kid wavey-id-2026-06-04 > .wrangler/zeroth-bootstrap.env
printf "\nexport ADMIN_TOKEN='%s'\n" "$(openssl rand -base64 32 | tr -d '\n')" >> .wrangler/zeroth-bootstrap.env
printf 'export ZEROTH_ADMIN_TOKEN=${ADMIN_TOKEN}\n' >> .wrangler/zeroth-bootstrap.env
chmod 600 .wrangler/zeroth-bootstrap.env
npm run zeroth:secrets:bootstrap:check
npm run zeroth:secrets:bootstrapnpm run zeroth:secrets:bootstrap uploads only JWT_KEY_ID,
JWT_ES256_PRIVATE_KEY, ADMIN_TOKEN or ADMIN_TOKEN_SHA256, and optional
admin allowlist or JWKS-rotation secrets from .wrangler/zeroth-bootstrap.env.
It does not require Apple, Google, or Spotify provider secrets. It still needs a
Cloudflare token with Workers Scripts secret-write permission.
Set provider and signing secrets:
export GOOGLE_CLIENT_SECRET=...
export APPLE_TEAM_ID=...
# APPLE_KEY_ID can be inferred from AuthKey_<KEYID>.p8 filenames.
export APPLE_PRIVATE_KEY_PATH=.wrangler/zeroth/AuthKey_YOURKEYID.p8
export SPOTIFY_CLIENT_SECRET=...
source <(npm run --silent zeroth:signing-key -- --kid wavey-id-2026-06-04)
# Optional during signing-key rotation:
# export JWT_PREVIOUS_PUBLIC_JWKS_JSON='{"keys":[...]}'
export ADMIN_TOKEN=...
# Optional after the first Zeroth admin user has logged in:
# export ADMIN_USER_IDS=usr_...
# export ADMIN_EMAILS=you@wavey.ai
# Optional if MAGIC_LINK_DELIVERY=resend:
# export RESEND_API_KEY=...
# Optional if MAGIC_LINK_DELIVERY=mailchannels:
# export MAILCHANNELS_API_KEY=...
export APPLE_APP_SITE_ASSOCIATION_JSON='{"webcredentials":{"apps":["<APPLE_TEAM_ID>.ai.wavey.infidelity"]}}'
npm run zeroth:secrets:check
npm run zeroth:secretsTo bring up Apple admin login before every active provider is ready, upload only the Apple provider material and optional admin session allowlist:
export APPLE_TEAM_ID=2D332SZF9P
# APPLE_KEY_ID can be inferred from AuthKey_<KEYID>.p8 filenames.
export APPLE_PRIVATE_KEY_PATH=.wrangler/zeroth/AuthKey_9A6Y2BQGRB.p8
# Optional after the first Zeroth admin user has logged in:
# export ADMIN_USER_IDS=usr_...
# export ADMIN_EMAILS=you@wavey.ai
npm run zeroth:secrets:apple:check
npm run zeroth:secrets:appleADMIN_TOKEN enables Zeroth's management APIs and the HTTP schema bootstrap
endpoint. Use ADMIN_TOKEN_SHA256 instead if you want to store only the
SHA-256 hex digest of the bearer token in Cloudflare.
After the first admin login, set ADMIN_USER_IDS or ADMIN_EMAILS to let the
Zeroth browser session administer id.wavey.ai itself; email matches require a
verified primary email. The admin UI has a Zeroth sign-in link that returns to
https://id.wavey.ai/admin, and the same-origin API calls work without a bearer
token once that session is allowlisted. Keep ADMIN_TOKEN as
bootstrap/emergency access.
JWT_PREVIOUS_PUBLIC_JWKS_JSON is optional; set it only during signing-key
rotation when existing relying apps still need retired public ES256 keys in
Zeroth's JWKS.
npm run zeroth:apple:status reports local Sign in with Apple readiness without
printing key material, client secrets, or admin tokens. The local Sign in with
Apple key cache lives under .wrangler/zeroth/AuthKey_<KEYID>.p8; that folder
is ignored by Git and should contain only provider-login key material. The
parent folder AppStore_AuthKey_*.p8 file is App Store Connect/admin material,
not Zeroth provider-login material, and the Zeroth secret helper refuses to use
it for APPLE_PRIVATE_KEY_PATH.
npm run zeroth:providers:status reports local Apple, Google, and Spotify
readiness without printing provider secrets. Disabled providers remain visible
but are not required. Use it before npm run zeroth:secrets to check that
active provider client IDs and provider secrets are present. Use
npm run zeroth:providers:status:remote after uploading secrets to verify the
deployed Worker secret bindings by name without reading secret values.
npm run zeroth:secrets:check validates the local secret environment, Apple
private-key path, Zeroth ES256 signing key format, Apple private-key PEM format,
and optional previous public JWKS without writing anything to Cloudflare.
Use npm run zeroth:signing-key -- --kid wavey-id-2026-06-04 --format json if
you want to archive the non-secret public JWKS record for future rotations.
Provider client IDs are non-secret Wrangler vars in wrangler.zeroth.jsonc:
DEFAULT_LOGIN_CLIENT_ID=wavey-browser
SESSION_COOKIE_DOMAIN=.wavey.ai
APPLE_CLIENT_ID=ai.wavey.zeroth
GOOGLE_CLIENT_ID=659630448576-rdjkvjjggtj8p4ibm772tivi3m6qiqsn.apps.googleusercontent.com
SPOTIFY_CLIENT_ID=9d756b59b3af4a7ebae549b6ad3f86d4
DISABLED_PROVIDERS=spotify
SESSION_COOKIE_DOMAIN=.wavey.ai is the Zeroth-native version of the useful
shared-cookie part of hyper-idp: first-party Wavey subdomains can receive the
same HttpOnly browser session cookie. It does not make that cookie available to
unrelated registrable domains such as bitneedle.com or infidelity.io; those
apps still use Zeroth through OIDC redirects and their own app-local sessions.
Spotify is intentionally disabled in this deployment until its app/account
restriction is cleared. Disabled providers remain visible in admin status, but
they are not required for /ready, rollout checks, or public login buttons.
For Spotify development-mode apps, clear that restriction by making sure the
Spotify app owner account has Premium, the test login user is allowlisted in
the app's Users Management tab, and Spotify's current-user profile endpoint
/v1/me returns HTTP 200 after authorization. Zeroth needs that profile call
because Spotify does not issue an OIDC ID token for this provider path.
After changing provider client IDs or the disabled-provider list, run the strict deployment config verifier and deployment preflight:
npm run zeroth:verify
npm run zeroth:deploy:preflight
npm run zeroth:rollout:statusThe strict verifier and Zeroth's runtime readiness checks reject scaffold
placeholders such as replace-with-*, changeme, and <...>. Use
npm run zeroth:verify:local only for local template checks before the real D1
database ID and provider client IDs exist.
npm run zeroth:deploy:preflight also checks remote D1 schema access, requires
at least the five seeded Wavey client rows, checks non-mutating Workers
deployment and secret API access, and runs Worker dry-run packaging. If it fails
at worker_api_read or worker_secrets_read with Cloudflare
Authentication error [code: 10000], the Cloudflare API token needs
Workers Scripts:Read and Workers Scripts:Edit for account
c57bb20727aa3564966d2bb693abddce before npm run zeroth:secrets or
npm run zeroth:deploy can succeed.
Use npm run zeroth:deploy:preflight:startup or
npm run zeroth:rollout:status:startup when you also want Wrangler startup
profiling. The startup profile parser fails the preflight when sampled startup
active CPU exceeds the local 10 ms guardrail; inspect the numeric result with
npm run zeroth:startup:profile after npm run zeroth:startup:check.
npm run zeroth:rollout:status condenses config, D1, Workers API, and live-host
state into blockers and next actions. Add -- --with-build to include Worker
dry-run packaging, or use npm run zeroth:rollout:require when automation must
fail unless the live host is fully Zeroth-ready.
After deploy and secret upload, run the live verifier. It checks discovery and
requires GET /ready to return 200 with ready=true for the active provider
set:
npm run zeroth:live:status
npm run zeroth:verify:livenpm run zeroth:live:status is non-strict rollout visibility. The live host
should report zeroth_ready once all active providers pass readiness; disabled
providers such as the current Spotify entry are omitted from public readiness.
Use npm run zeroth:live:require when a script must fail unless discovery is
Zeroth-owned.
When the bootstrap token is available locally, run the admin live verifier too.
It checks GET /__zeroth/db/status and the seeded registered clients so a live
deployment cannot pass with provider config but missing D1 schema or client
rows:
export ZEROTH_ADMIN_TOKEN="$ADMIN_TOKEN"
npm run zeroth:verify:live:adminBefore provider credentials are ready, use the bootstrap verifier to prove the
deployed backend, admin token, D1 schema, and seeded clients are working while
allowing /ready to remain red for whichever active providers are still
missing:
npm run zeroth:verify:live:admin:bootstrapFor the current "try the deployed backend" phase, use the backend status gate:
npm run zeroth:backend:status
npm run zeroth:backend:requireThis command requires live discovery, signing config, D1 schema, seeded clients, Workers API access, Worker secret-list access, active provider readiness, hosted Apple/Google login redirects, public route-alias compatibility, D1-backed user/event/local-auth persistence evidence, and the 10 ms startup guardrail.
To inspect only the D1-backed persistence surface, run:
npm run zeroth:persistence:statusIt verifies the required Zeroth D1 tables and migrations, seeded clients, persisted users, at least one admin user, audit events, local-auth credential storage, and provider/admin status APIs without printing bearer tokens.
To inspect only the hosted login path, run:
npm run zeroth:login:statusIt verifies that active providers set a transaction cookie and redirect to the expected upstream authorization host, and that deployment-disabled providers are not shown in the hosted picker.
To inspect only public Zeroth route compatibility, run:
npm run zeroth:routes:statusIt verifies /routes advertises the common hosted-login, admin, callback, and
magic-link aliases, then probes those live paths so router-level not_found
regressions block the strict replacement gate.
To prove the Spotify external account gate after fixing the app owner Premium and Users Management allowlist state, run:
SPOTIFY_ACCESS_TOKEN=... npm run zeroth:spotify:status
SPOTIFY_ACCESS_TOKEN=... npm run zeroth:spotify:requireThe probe calls Spotify's current-user profile endpoint /v1/me, checks that
the profile returns HTTP 200 with account_id or legacy id for Zeroth account
linking, and does not print the access token or profile identifiers.
To inspect magic-link delivery, run:
npm run zeroth:email:status
npm run zeroth:email:send-testWavey currently uses Zeroth's default MAGIC_LINK_DELIVERY=cloudflare_email.
Cloudflare Email Service requires an active Workers Paid account plan. The email
status script is transport-aware: for cloudflare_email it checks the account
subscriptions, the send_email binding, sender restrictions, Email Sending
DNS/status APIs, and live Zeroth magic-link delivery evidence without printing
Cloudflare credentials or admin tokens. If the deployment switches to
MAGIC_LINK_DELIVERY=webhook, the same status command checks the HTTPS webhook
configuration and live delivery evidence instead of reporting Cloudflare Email
Service blockers. Zeroth also supports MAGIC_LINK_DELIVERY=resend with
RESEND_API_KEY/MAGIC_LINK_RESEND_API_KEY, and
MAGIC_LINK_DELIVERY=mailchannels with
MAILCHANNELS_API_KEY/MAGIC_LINK_MAILCHANNELS_API_KEY; in those modes the
status command checks remote Worker secret presence and live delivery evidence.
npm run zeroth:backend:status includes the same result as email_summary and
adds magic-link delivery blockers to the stricter zeroth_deployment gate.
The output separates live issuer readiness from full Zeroth deployment
readiness. A
phase of zeroth_ready means id.wavey.ai is serving the Zeroth issuer and
active providers are usable. The zeroth_deployment block is stricter: it
requires Apple, Google, and Spotify target provider coverage, the seeded relying
clients, the Zeroth-owned route, D1-backed user/admin/audit persistence, and
local-auth delivery evidence. Today that block can remain ready:false while
Apple/Google login is usable, for example while Spotify is disabled by
deployment or the selected magic-link sender has not proven delivery.
DEFAULT_LOGIN_CLIENT_ID is used by browser SSO compatibility entry points such as
/login?return_to=... when the relying app does not send an explicit
client_id.
For a fresh launch, no live relying service needs migration. Create new Apple Developer material when Zeroth is otherwise ready, but do not delete existing Apple apps or identifiers:
1. Create or choose a primary Wavey App ID with Sign in with Apple enabled.
2. Create a new Sign in with Apple key and record Team ID, Key ID, and .p8.
3. Create a new Sign in with Apple Service ID for id.wavey.ai.
4. Register https://id.wavey.ai/oauth2/callback as the Service ID return URL.
5. Set APPLE_CLIENT_ID to that Service ID in wrangler.zeroth.jsonc.
6. Store APPLE_TEAM_ID, APPLE_KEY_ID, and APPLE_PRIVATE_KEY_PATH through npm run zeroth:secrets:apple.
7. Set APPLE_APP_SITE_ASSOCIATION_JSON only after the final native bundle IDs are known.
npm run zeroth:apple:provision covers the API-safe part of that list. It
creates or reuses the primary ai.wavey.id App ID and enables Sign in with
Apple on that App ID. It defaults to a dry run; pass -- --apply to mutate
Apple Developer provisioning records:
export ASC_ISSUER_ID=...
npm run zeroth:apple:provision
npm run zeroth:apple:provision -- --applyApple's App Store Connect API can manage bundle IDs and their capabilities when
called with a team API key and issuer ID, but current public API coverage does
not include creating the Sign in with Apple Services ID or downloading a new
Sign in with Apple private key. Those two fresh resources are Developer portal
actions; the AppStore_AuthKey_*.p8 API/admin key is not the provider-login
private key that Zeroth needs.
Apple's APPLE_CLIENT_SECRET is the Sign in with Apple client-secret JWT.
Zeroth can now mint it at runtime from APPLE_TEAM_ID, APPLE_KEY_ID, and
APPLE_PRIVATE_KEY or APPLE_PRIVATE_KEY_PATH; the secret helper stores the
private key in Cloudflare as APPLE_PRIVATE_KEY. A static JWT is still accepted
if APPLE_CLIENT_SECRET is set. Generate a static value from the generic CLI
without mutating Apple Developer records:
Do not reuse the parent-folder ../AppStore_AuthKey_*.p8 admin credential for
Sign in with Apple provider login. Zeroth expects a fresh Sign in with Apple key,
normally downloaded as AuthKey_<KEYID>.p8; the secret helper can infer
APPLE_KEY_ID only from that exact filename shape. Zeroth still needs the Apple
Team ID and the Service ID used as APPLE_CLIENT_ID.
cd ../zeroth
cargo run -p zeroth-cli -- apple-client-secret \
--team-id "$APPLE_TEAM_ID" \
--key-id "$APPLE_KEY_ID" \
--client-id "$APPLE_CLIENT_ID" \
--private-key "$APPLE_PRIVATE_KEY_PATH"The seeded public clients are:
wavey-browser default browser SSO client for wavey.ai, bitneedle.com, and infidelity.io
infidelity-macos http://localhost/oidc-callback
wavey-ios wavey://auth/callback and current iOS bundle callbacks
bitneedle-web https://bitneedle.com/auth/callback, https://www.bitneedle.com/auth/callback
infidelity-web https://infidelity.io/auth/callback, https://www.infidelity.io/auth/callback
All seeded clients currently set allowed_email_domains_json to [], so
provider login is not restricted by email domain. Use Zeroth's generic
allowedEmailDomains client policy later for first-party-only or admin-only
clients; do not apply a global Wavey domain restriction to Bitneedle,
Infidelity, native, or Spotify-facing clients.
Zeroth treats unported loopback client redirects such as
http://localhost/oidc-callback as a native-app policy that allows an ephemeral
loopback port on the same host/path, matching the current Infidelity Swift OIDC
client.
Production host:
https://id.wavey.ai
Primary Zeroth endpoints:
GET /.well-known/openid-configuration
GET /.well-known/jwks.json
GET /.well-known/apple-app-site-association
GET /ready
GET /login
GET /account
GET /admin
GET /admin/clients
GET /providers/status
GET /clients
POST /clients
DELETE /clients?client_id=...
GET /users
GET /users?user_id=...
PATCH /users?user_id=...
GET /events
GET /__zeroth/db/status
POST /__zeroth/db/ensure
GET /authorize
POST /oauth/token
POST /oauth/revoke
GET /userinfo
GET /oauth2/callback
GET /session
GET /sessions
GET /profile
GET /identities
GET /identities/link
GET /validate
GET /logout
POST /logout
The Zeroth discovery document uses https://id.wavey.ai as issuer and publishes
Zeroth-owned ES256 JWKS. Native clients should validate Zeroth ID tokens, not
old upstream issuer tokens. Zeroth ID tokens include email/email_verified
and name/picture only when the client requested the email and profile
scopes. Authorization-code redirects use query parameters and include
iss=https://id.wavey.ai so Swift and browser clients can bind responses to
this issuer. Clients that send response_mode must send query; unsupported
downstream response modes return invalid_request before provider login starts.
Provider callback state is consumed with a conditional D1 update before Zeroth
exchanges an Apple, Google, or Spotify code or creates local sessions/codes, so
a replayed or raced provider callback returns invalid_request. The callback
state must also match Zeroth's short-lived HttpOnly transaction cookie, scoped to
/oauth2/callback and marked SameSite=None for Apple's form_post. Clients
can use prompt=none for silent SSO: an active Zeroth
browser session that satisfies max_age returns a code, while a missing or
too-old session returns login_required on the registered redirect. Use
prompt=login or max_age=0 when a Swift or browser client needs fresh
provider authentication. Once a client redirect URI has been validated,
authorization request failures return to that same redirect with error,
original state, and iss rather than JSON. Discovery also advertises
https://id.wavey.ai/logout as the OIDC end-session endpoint; post-logout
redirects are accepted only for the resolved registered client.
Registered clients can be seeded with zeroth.clients.sql or managed after
deploy through Zeroth itself. The admin gate accepts the bootstrap bearer token
or an allowlisted Zeroth browser session, and covers schema bootstrap, user
lifecycle, and provider-readiness/audit APIs. Disabling a client stops new
authorization/token exchanges and also makes /userinfo, /validate, and
session CORS checks reject that client from D1:
Zeroth authorization codes are consumed with a conditional D1 update before
credentials are minted, so a replayed or raced code returns invalid_grant.
Refresh tokens are rotated on every refresh-token grant and are bound to the
browser session that created the authorization code, including silent
prompt=none SSO, and preserve the original auth_time in refreshed ID tokens.
The replacement refresh token is issued only after the conditional D1 rotation
update wins. If a rotated token is presented again by the same client, or if the
rotation loses a race, Zeroth revokes the active session-scoped token family
before returning invalid_grant. Session logout and user-initiated session
revocation also revoke the refresh-token family bound to that browser session.
curl -H "Authorization: Bearer $ADMIN_TOKEN" \
"https://id.wavey.ai/clients"
curl -H "Authorization: Bearer $ADMIN_TOKEN" \
"https://id.wavey.ai/users"
curl -H "Authorization: Bearer $ADMIN_TOKEN" \
"https://id.wavey.ai/providers/status"
curl -H "Authorization: Bearer $ADMIN_TOKEN" \
"https://id.wavey.ai/events"
curl -H "Authorization: Bearer $ADMIN_TOKEN" \
"https://id.wavey.ai/events?event_type=session.login&client_id=wavey-ios"
curl -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
"https://id.wavey.ai/__zeroth/db/ensure"The same APIs are available through the hosted management UI at:
https://id.wavey.ai/admin
https://id.wavey.ai/admin/clients
Use the bootstrap token on first launch. After provider login succeeds, sign in
from /admin, copy the created user ID or verified email into ADMIN_USER_IDS
or ADMIN_EMAILS, upload secrets again, and then the id.wavey.ai admin UI can
administer Zeroth through its own browser session. The admin UI shows the D1
schema/client preflight before loading users, events, and clients, so missing
schema or seed rows are visible without checking raw JSON manually.
Before connecting apps, GET https://id.wavey.ai/ready should return 200.
It checks the HTTPS issuer URL, parseable Zeroth signing material, and configured
active provider credentials without reading D1 or returning secret values.
Placeholder provider IDs or secrets on active providers are reported as
unconfigured and keep readiness false.
Worker route:
id.wavey.ai/*
Zone:
wavey.ai
DNS:
CNAME id.wavey.ai -> wavey.ai, proxied
Deployment config lives in wrangler.zeroth.jsonc; there is no separate old
Worker config in this repo.
Sign in with Apple provider token exchange needs either APPLE_CLIENT_SECRET
or the runtime signing inputs APPLE_TEAM_ID, APPLE_KEY_ID, and
APPLE_PRIVATE_KEY/APPLE_PRIVATE_KEY_PATH.
Infidelity macOS Associated Domains entitlement:
webcredentials:id.wavey.ai
Apple App Site Association URL served by this Worker:
https://id.wavey.ai/.well-known/apple-app-site-association
Apple App Site Association payload shape:
{
"webcredentials": {
"apps": [
"<APPLE_TEAM_ID>.ai.wavey.infidelity"
]
}
}Interactive login URL for checking the shared Zeroth browser session:
https://id.wavey.ai/login?return_to=https%3A%2F%2Fbitneedle.com%2Fdataroom%2F
That uses the deployment's DEFAULT_LOGIN_CLIENT_ID=wavey-browser. A narrower
client can be selected explicitly with client_id=bitneedle-web.
Server-side product gates should use the OIDC authorization-code flow instead
of relying on the id.wavey.ai cookie. Generate a random state, nonce, and
PKCE code_verifier, store those in the product's own short-lived callback
state, and redirect to Zeroth:
https://id.wavey.ai/authorize?client_id=bitneedle-web&redirect_uri=https%3A%2F%2Fbitneedle.com%2Fauth%2Fcallback&response_type=code&scope=openid%20email%20profile&state=...&nonce=...&code_challenge=...&code_challenge_method=S256
On https://bitneedle.com/auth/callback, verify state and
iss=https://id.wavey.ai, exchange the code at POST /oauth/token with the
same code_verifier, validate the access token by calling Zeroth /userinfo or
verifying Zeroth's JWKS/issuer/audience locally, and then set a Bitneedle-local
session cookie for protected content. The generic
zeroth-oidc crate now contains helpers for PKCE challenge calculation,
authorization URL construction, callback parsing, token form encoding, and token
response decoding plus ES256 Zeroth token verification so product Workers do
not need to hand-roll those details.
Session/profile check from browser JS only works when the browser is allowed to
send the id.wavey.ai cookie:
const res = await fetch("https://id.wavey.ai/session", {
credentials: "include",
});Server-side Worker validation compatibility endpoint:
https://id.wavey.ai/validate
Note: browser cookies from id.wavey.ai are not sent to bitneedle.com.
Bitneedle's dataroom login remains disabled for now with
BITNEEDLE_AUTH_BYPASS = "always". Before restoring a server-side Bitneedle
gate, wire the callback/token handoff above and store a Bitneedle-local session.
Website session/profile check:
const res = await fetch("https://id.wavey.ai/session", {
credentials: "include",
});macOS OIDC issuer:
https://id.wavey.ai
macOS login is still disabled in the current app UI. Zeroth is the issuer to
use when that UI is wired back up. Apple and Google web login are configured on
id.wavey.ai; Spotify is present as a configured provider but disabled by
DISABLED_PROVIDERS=spotify until the Spotify app/account restriction is
cleared.
- The Worker stores browser session state in D1 and keeps only an opaque session id in the secure cookie.
- No KV or Durable Object is required for the current D1-backed session model.
- Zeroth is the shared issuer of ID tokens for this deployment.
id.wavey.aiis the only Worker that should own shared login. Do not deploy a separateid.bitneedle.comauth Worker.