Welcome back

Sign in to cloudflare-auth

New here? Create an account

Looking for integration details? Read the docs

Create account

Start with email and password

Already have an account? Sign in

New to cloudflare-auth? How accounts work

Profile

Your account and session details.

Email
Username
Created
User ID

Session status

Current session

Active · Expires in 24h

This session will expire at —.

API Base URL

Your authentication API base URL

Copied

Regenerating your token will invalidate the current token and issue a new one.

Applications

Apply for an App ID to connect each product. Secrets are shown only once.

App created

Copy this secret now. You will not be able to see it again.

sec_…

Register a new app

Your apps

Documentation

Choose the guide that matches how you use cloudflare-auth — integrate the API as a developer, or manage your own account as a user.

Docs/Developers

Developer guide

Integrate cloudflare-auth into your app with email/password accounts and revocable sessions.

Quick start

Base URL for this prototype environment:

https://cloudflare-auth.veegn.workers.dev

Local Worker (during development):

http://127.0.0.1:8787
  1. Register a user with POST /auth/register.
  2. Receive a JWT token and store it on the client.
  3. Call protected routes with Authorization: Bearer <token>.
  4. Revoke the session with POST /auth/logout when done.

API reference

Method Path Auth Description
POST /auth/register Create account, auto sign-in, return token
POST /auth/login Exchange email + password for a token
GET /auth/me Bearer Return the current user profile
POST /auth/logout Bearer Revoke the current session
GET /health Liveness check

POST /auth/register

Request body (JSON):

{ "email": "alice@example.com", "username": "alice", "password": "password123" }

Rules: email must be valid; username ^[A-Za-z0-9_]{3,32}$; password ≥ 8 characters.

Success 201:

{ "user": { "id": "…", "email": "alice@example.com", "username": "alice", "createdAt": "2026-09-17" }, "token": "eyJhbGciOi…", "expiresIn": 86400 }

POST /auth/login

Request body:

{ "email": "alice@example.com", "password": "password123" }

Success 200 returns the same shape as register. Invalid credentials always return 401 with invalid_credentials — the API does not reveal whether the email exists.

GET /auth/me

Header:

Authorization: Bearer <token>

Success 200:

{ "user": { "id": "…", "email": "alice@example.com", "username": "alice", "createdAt": "…" } }

POST /auth/logout

Requires the Bearer token. Success 200 {"ok":true}. The session row is deleted; the same token cannot be reused.

App ID integration guide

Each product that calls this auth service should use its own App ID. That keeps integrations isolated — you can rotate or revoke one app without affecting others.

1

Apply

Developer creates an application and receives App ID + one-time Secret.

2

Configure

Store credentials on your server only (env / secret manager).

3

Call auth

Backend sends X-App-Id + X-App-Secret on register/login.

4

Operate

Use the user token; rotate secret or revoke app when needed.

Who holds which credential

Developer console

  • Account email / password
  • Issues App ID + Secret
  • Rotate / revoke apps

Your backend

  • APP_ID + APP_SECRET
  • Attaches app headers
  • Never ships secret to clients

End user / client

  • Email + password
  • Receives user token
  • Never sees App Secret

Integration flow

  1. Create a developer account — sign up on this console (or via POST /auth/register).
  2. Apply for an App ID — on the Applications page, or via POST /apps.
  3. Store credentials — save app_… and the one-time sec_… in your server secret store.
  4. Call register / login — send both app headers from your backend when signing end users in.
  5. Use the user token — call GET /auth/me and logout with Authorization: Bearer <user_token>.
  6. Operate the app — rotate the secret if leaked; revoke the app to block all further logins with it.

Step 1 — Apply for credentials

UI: Sign in → ApplicationsCreate application → copy App ID + Secret immediately (Secret is shown once).

API: with a developer Bearer token:

curl -X POST $BASE/apps \ -H "content-type: application/json" \ -H "Authorization: Bearer <developer_token>" \ -d '{"name":"Acme Dashboard","description":"Prod web"}' # Response (201) { "app": { "id": "…", "appId": "app_e14bab3b…", "name": "Acme Dashboard", "status": "active" }, "appSecret": "sec_7fd81b96…", "warning": "Store appSecret now. It will not be shown again." }

List / inspect apps you own:

curl $BASE/apps -H "Authorization: Bearer <developer_token>" # → { "apps": [ { "id", "appId", "name", "status", "createdAt", … } ] }

Step 2 — Configure your backend

Environment variables (example):

AUTH_BASE=https://cloudflare-auth.veegn.workers.dev APP_ID=app_e14bab3b6711ae118ae68418 APP_SECRET=sec_7fd81b9627936e5c…
Keep secrets server-side. Never put APP_SECRET in browser or mobile clients. Only your backend attaches X-App-Id / X-App-Secret.

Step 3 — Call auth APIs with app credentials

Send both headers from your server on /auth/register and /auth/login:

POST /auth/login HTTP/1.1 content-type: application/json X-App-Id: app_e14bab3b6711ae118ae68418 X-App-Secret: sec_7fd81b9627936e5c… {"email":"alice@example.com","password":"password123"}

Success responses include the bound appId. Sessions created this way are tied to that app.

# Register an end user through your app curl -X POST $BASE/auth/register \ -H "content-type: application/json" \ -H "X-App-Id: $APP_ID" \ -H "X-App-Secret: $APP_SECRET" \ -d '{"email":"alice@example.com","username":"alice","password":"password123"}' # → 201 { user, token, expiresIn, appId } # Login an existing end user curl -X POST $BASE/auth/login \ -H "content-type: application/json" \ -H "X-App-Id: $APP_ID" \ -H "X-App-Secret: $APP_SECRET" \ -d '{"email":"alice@example.com","password":"password123"}' # → 200 { user, token, expiresIn, appId }

Omitting both headers still works for direct first-party use. Providing only one of the two is rejected with 401 invalid_app_credentials.

Step 4 — Use the user session

After login/register, your client (or BFF) uses only the user token — never the App Secret:

curl $BASE/auth/me \ -H "Authorization: Bearer <user_token>" # → { "user": { … }, "appId": "app_…" } curl -X POST $BASE/auth/logout \ -H "Authorization: Bearer <user_token>" # → { "ok": true }

Step 5 — Lifecycle

ActionWhenEffect
Rotate secret Suspected leak / periodic rotation Old sec_… stops working immediately; new one returned once
Revoke app Decommission product / security incident All further register/login with that App ID return 401 invalid_app_credentials
curl -X POST $BASE/apps/<internal-id>/rotate-secret \ -H "Authorization: Bearer <developer_token>" # → { app, appSecret, warning } curl -X POST $BASE/apps/<internal-id>/revoke \ -H "Authorization: Bearer <developer_token>" # → { app: { status: "revoked", … } }

Server-side example (Node)

// .env: APP_ID, APP_SECRET, AUTH_BASE const headers = { "content-type": "application/json", "X-App-Id": process.env.APP_ID, "X-App-Secret": process.env.APP_SECRET, }; export async function registerEndUser({ email, username, password }) { const res = await fetch(`${process.env.AUTH_BASE}/auth/register`, { method: "POST", headers, body: JSON.stringify({ email, username, password }), }); const data = await res.json(); if (!res.ok) throw new Error(data.message || "register failed"); // data.token → give to your client; never expose APP_SECRET return data; // { user, token, expiresIn, appId } } export async function loginEndUser(email, password) { const res = await fetch(`${process.env.AUTH_BASE}/auth/login`, { method: "POST", headers, body: JSON.stringify({ email, password }), }); const data = await res.json(); if (!res.ok) throw new Error(data.message || "login failed"); return data; } export async function getMe(userToken) { const res = await fetch(`${process.env.AUTH_BASE}/auth/me`, { headers: { Authorization: `Bearer ${userToken}` }, }); return res.json(); }

Troubleshooting app credentials

ResponseLikely causeFix
401 invalid_app_credentials Only one of X-App-Id / X-App-Secret sent Always send both headers together
401 invalid_app_credentials Wrong secret or secret already rotated Use the latest secret; rotate again if lost
401 invalid_app_credentials App revoked or appId typo Check Applications list; create a new app if revoked
401 invalid_credentials End-user email/password wrong Unrelated to App ID — fix user credentials
401 unauthorized Missing/expired user token on /auth/me Send Authorization: Bearer <user_token>

Manage apps (developer session required)

MethodPathDescription
POST/appsCreate app — returns App ID + one-time secret
GET/appsList your applications
GET/apps/:idGet one application
POST/apps/:id/rotate-secretIssue a new secret
POST/apps/:id/revokeRevoke the application

Create body:

{ "name": "Acme Dashboard", "description": "Optional" }

Integration checklist

  • One App ID per product / environment (dev / staging / prod)
  • Secret stored in env / secret manager, not in git
  • App headers only on server-to-server calls
  • User tokens only on client after login (or via your BFF)
  • Rotate plan documented; revoke path tested

Error codes

StatuserrorWhen
400invalid_jsonBody is not valid JSON
400invalid_emailEmail format rejected
400invalid_usernameUsername pattern rejected
400weak_passwordPassword shorter than 8
401invalid_credentialsLogin failed
401unauthorizedMissing / expired / revoked token
401invalid_app_credentialsBad or revoked X-App-Id / X-App-Secret
409conflictEmail or username already taken
404not_foundUnknown route
500internal_errorUnexpected server failure

Example: fetch client

const res = await fetch(`${BASE}/auth/login`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email, password }), }); const { user, token, expiresIn } = await res.json(); const me = await fetch(`${BASE}/auth/me`, { headers: { Authorization: `Bearer ${token}` }, });

Local development

npm install npm run db:schema:local npm run dev # http://127.0.0.1:8787
Security notes. Passwords are stored as PBKDF2-SHA256 (100k iterations). Sessions are revocable server-side. Set a long JWT_SECRET with wrangler secret put JWT_SECRET before production. Prefer httpOnly cookies over localStorage when shipping a real frontend.

Docs/Users

User guide

How to create an account, sign in, keep your session secure, and sign out.

Create an account

  1. Open Create an account from the sign-in screen.
  2. Enter a valid email, a username, and a password.
  3. Confirm your password, then choose Create account.

What we ask for

  • Email — used to sign in. Must look like name@example.com.
  • Username — 3–32 characters: letters, numbers, underscore only.
  • Password — at least 8 characters. Longer is better.
If the email or username is already taken, you’ll see Email or username already taken. Try a different value — we never show who already owns an email.

Sign in

  1. Go to the sign-in screen.
  2. Enter the email and password you registered with.
  3. Choose Sign in.

Wrong email or password shows a single message: Invalid email or password. That is intentional — it does not tell you whether the account exists.

Live service. This console talks to the deployed Worker API on the same origin. Create an account to manage App IDs.

Your profile page

After a successful sign-in you land on Profile, which shows:

  • Email, Username, Created, and User ID
  • Session status — a green Active pill and when this session expires
  • API Base URL — only relevant if you are also integrating the API

These fields mirror the account we store for you. Passwords are never shown here (or anywhere).

Sessions & security

  • Signing in creates a session that stays valid until it expires (default 24 hours) or you sign out.
  • Signing out immediately revokes that session — the same token cannot be used again.
  • If a session expires or is revoked, you are returned to the sign-in screen.
  • On a shared computer, always Sign out when finished.

What we store

  • Email and username (as you entered them)
  • A one-way password hash — never your password in plain text
  • Account creation time and active session records

Sign out

  1. Click Sign out in the sidebar.
  2. You return to the sign-in screen; the previous session is revoked.

Troubleshooting

You seeWhat to do
Invalid email or password Check spelling and caps lock; reset is not available in this version — register again if needed.
Email is invalid Use a full address like name@example.com.
Password must be at least 8 characters Choose a longer password and confirm it matches.
Email or username already taken Pick a different email or username.
Sent back to sign-in unexpectedly Your session expired or was revoked. Sign in again.

Need the API?

If you are building an app on top of cloudflare-auth, switch to the developer guide for endpoints and examples.