Authentication errors
Fix sign-up 403s, rate-limited sign-ins, API keys with the wrong permissions, and stale sessions.
#Sign-up returns 403 signup_forbidden
#Problem
New users can't register. POST /api/auth/sign-up/email returns 403 with the error code signup_forbidden, even though the request body is valid.
#Cause
Self-registration is controlled by RBAC, not an environment variable. Sign-up is allowed only when the caller's role has the system/users:create permission. Unauthenticated callers are checked as the public role, which doesn't have this permission by default — so public sign-up is disabled out of the box.
The one exception is a fresh install: when no users exist yet, the first sign-up is always allowed so you can create the initial admin account.
#Fix
Choose the registration model you want:
- Open registration — grant
system/users:createto thepublicrole in the access control settings. Anyone can then sign up. - Invite-only — keep the default. An admin whose role has
system/users:createcreates accounts through the user management UI orPOST /api/v1/users.
#Prevention
Decide on your registration model when you set up the instance. Review which roles hold system/users:create after any role changes — granting it to public opens registration to everyone.
#Sign-in returns 429 rate_limited
#Problem
Sign-in attempts fail with 429 and the error code rate_limited. The response includes a Retry-After header.
#Cause
All /api/auth/* endpoints are rate limited to 5 requests per minute per IP address to protect against brute-force attacks. The counter is atomic (backed by a Durable Object) and persists across Worker restarts, so rapid retries don't reset it.
#Fix
- Wait for the number of seconds shown in the
Retry-Afterresponse header, then try again. - Check the
X-RateLimit-Remainingheader on auth responses to see how many attempts you have left in the current window. - If your app retries failed sign-ins automatically, add a backoff so the retries don't consume the whole window.
#Prevention
Don't loop sign-in requests. Cache the session after a successful sign-in and reuse it — a session stays valid until it expires or is revoked, so there is no need to re-authenticate per request.
#Auth requests return 503 "Rate limiting unavailable"
#Problem
Requests to /api/auth/* fail with 503 and the message Rate limiting unavailable. Request blocked. Other API endpoints keep working.
#Cause
Authentication endpoints fail closed by design. If the rate-limiting infrastructure (the Durable Object and the KV fallback) is unreachable, EmuView blocks auth requests rather than allowing unlimited sign-in attempts. Non-auth endpoints fail open to preserve availability, which is why the rest of the API is unaffected.
#Fix
- Check the health of your Cloudflare Workers deployment — this usually indicates a missing or misconfigured
RATE_LIMITERDurable Object binding orPOLICY_CACHEKV binding. - Verify both bindings exist in your
wrangler.tomland redeploy.
#Prevention
Keep the Durable Object and KV bindings from the deployment template intact. Removing them doesn't disable rate limiting — it disables authentication.
#API key is denied actions it should be allowed to perform
#Problem
Requests authenticated with an API key return 403 forbidden for operations you expected the key to perform.
#Cause
An API key's permissions come from the RBAC role assigned to it. If you create a key without a roleId, it falls back to the built-in api role, which may not include the permissions you intended.
#Fix
- Create a new key with an explicit role: pass
roleIdin the body ofPOST /api/auth/api-keys. - The role must belong to your project, and it can't be
super_admin— API keys are never allowed that role. - Check what the key's role can actually do with the Effective Access tab of the Access Inspector (System → Access), which shows effective CRUD permissions per resource for any user, role, or crew.
#Prevention
Assign a role explicitly whenever you create an API key. Create dedicated least-privilege roles for machine access instead of reusing broad user roles. See API keys for details.
#Role or session changes don't take effect immediately
#Problem
You changed a user's role, or updated authentication settings, but requests still behave as if the old configuration applies.
#Cause
Two caches are involved:
- Sessions are cached for up to 5 minutes. Role changes made through the user management UI set a revocation flag that invalidates the cached session, but sessions changed by other means can stay stale until the cache expires.
- Settings (including authentication settings such as trusted origins) are cached for up to 60 seconds.
#Fix
- For a stale session, have the affected user sign out and sign back in — signing out deletes the cached session immediately.
- For stale settings, wait up to a minute and retry.
#Prevention
Make role changes through the user management UI so revocation flags are set for you. When testing configuration changes, allow the cache windows above before concluding a change didn't work.