Account
Sign in
One account, four sign-in methods, and a single rule: every account is email-verified before the first session is issued.
Methods
| Method | How it works | Email verified by |
|---|---|---|
| Magic link | Enter your email, receive a one-time link, click it, you're in. | Clicking the link. |
| Email + password | Register with a password ≥ 10 characters. The server stores a PBKDF2 hash; no session is issued until you verify. | Magic link sent from /register or /login. |
| GitHub OAuth | Standard OAuth 2.0 code exchange against github.com. | Skipped if GitHub returns email_verified: true; otherwise a magic link is sent. |
Why mandatory verification?
The free AI gateway is rate-limited per account, not per IP. Email verification is the cheapest reasonable proof that two accounts belong to two different humans, and it keeps the bar low (no phone numbers, no SMS, no captcha). Even password sign-ins re-send a magic link on any login attempt where the email is still unverified — so a single round-trip ever, then it's out of the way.
Passwords
- Stored as PBKDF2 hashes using Web Crypto — no plaintext, no retrievable form.
- Minimum length is 10 characters; there is no maximum-strength rule. Long passphrases beat character classes.
- We don't expose a password-reset flow today. To rotate, use a magic-link sign-in (it works for any email on the account) and re-set from /account.
Sessions and tokens
A successful sign-in returns two tokens:
- Access token — short-lived (15 min default), signed JWT. Sent as a Bearer on every API request, or read from the
xgoose_sessioncookie when you stay in-browser. - Refresh token — long-lived (60 days default), opaque, stored in an HTTP-only cookie. Trade it in at
POST /auth/refreshfor a fresh access token. Refresh tokens rotate on every use — the old one is revoked immediately.
You can revoke sessions globally from /account — useful if you suspect a leaked token or paired the extension on a machine you no longer own.
Admin promotion
Operators of a self-hosted deployment can list emails in the worker's ADMIN_EMAILS variable; matching accounts are auto-promoted to is_admin = 1 on next sign-in. Once promoted, you can promote others from /admin/user. The worker refuses to demote the last admin to avoid lockouts.
Deleting your account
From /account you can permanently delete your account. This:
- Revokes all active sessions and refresh tokens.
- Hard-deletes your identities (GitHub and email rows).
- Replaces
owner_user_idon any skills you published withNULL— the skills stay public, unowned, and can be re-claimed by admins on request. - Drops your quota bucket and AI request log entries within 30 days.
There is no soft-undo; if you want the data back, file an issue beforehand.