Authentication
HostEdge Auth adds sign-in to an app that runs on HostEdge. Your users live in your project database, so they never leave your project and you can query them with SQL. It works in a Worker or the server side of a framework.
It covers:
- email and password, with sessions
- magic links (sign in from an emailed link)
- password reset
- optional email confirmation
- sign-in with Google or GitHub
- rate limits that slow down guessing and email abuse
Set it up#
- Open Project › Storage and open a SQL database (add one if you have none).
- In the Authentication panel choose Set up authentication. This creates the
auth_*tables. - Download
hostedge-auth.tsfrom the panel, or fetch it fromhttps://hostedge.app/auth-kit/hostedge-auth.ts, and put it in your project. It is one file with no dependencies. - Use it in your Worker, then redeploy:
import { createAuth } from './hostedge-auth'
export default {
async fetch(request, env) {
const auth = createAuth(env.DB, { env })
const response = await auth.handle(request) // everything under /auth/…
if (response) return response
const user = await auth.getUser(request) // { id, email } or null
if (!user) return new Response('Sign in first', { status: 401 })
return new Response(`Hello ${user.email}`)
},
}
Pass env so HostEdge can send your emails (see below). The panel also lists the people who signed up, with Sign out everywhere, Disable and Delete for each.
Endpoints#
auth.handle(request) answers these. POSTs take a JSON body and must send content-type: application/json, which also protects them from cross-site forms.
| Request | What it does |
|---|---|
POST /auth/sign-up { email, password } | Creates the account and signs in (or sends a confirmation) |
POST /auth/sign-in { email, password } | Signs in |
POST /auth/sign-out | Ends this browser's session |
GET /auth/me | { user }, or { user: null } |
POST /auth/magic-link { email, next? } | Emails a one-time sign-in link (creates the account if new) |
GET /auth/verify?token=…&next=/ | The link in that email: signs in and redirects to next |
POST /auth/reset-request { email } | Emails a password reset link |
POST /auth/reset { token, password } | Sets the new password, signs out other devices, signs in |
GET /auth/oauth/github and /auth/oauth/google | Starts sign-in with the provider |
Passwords need at least 8 characters. next only accepts paths on your own site.
The reset email links to /reset-password?token=… on your site. Build that page: a form that sends the token and a new password to POST /auth/reset.
Emails#
HostEdge sends the magic-link, reset and confirmation emails for you, from its own sender and with your project's name, so there is nothing to set up. Every deploy adds HOSTEDGE_PROJECT_ID, HOSTEDGE_MAIL_URL and HOSTEDGE_MAIL_SECRET to your Worker; passing env to createAuth is all it takes.
| Plan | Auth emails per day, per project |
|---|---|
| Free | 50 |
| Starter | 500 |
| Pro | 2,000 |
| Agency | 10,000 |
One address receives at most 5 emails an hour from a project, and links can only point at your project's own addresses.
To send them yourself (Resend, Postmark, anything), pass a function instead:
createAuth(env.DB, {
sendEmail: async ({ to, kind, url }) => {
// kind is 'magic_link', 'reset' or 'confirm'
await myMailer.send({ to, subject: 'Your link', text: url })
},
})
Confirm emails#
Add confirmEmail: true to make people click an emailed link before they can sign in with a password. Until then, sign-in answers email_not_verified.
Google and GitHub#
Create an OAuth app with the provider and give it this redirect address:
https://your-site.example/auth/oauth/github/callback
https://your-site.example/auth/oauth/google/callback
Store the client ID and secret as environment variables and pass them in:
createAuth(env.DB, {
env,
oauth: {
github: { clientId: env.GITHUB_ID, clientSecret: env.GITHUB_SECRET },
google: { clientId: env.GOOGLE_ID, clientSecret: env.GOOGLE_SECRET },
},
})
Link people to /auth/oauth/github?next=/dashboard. Only a provider's verified email is accepted, and signing in with a provider uses the same account as a magic link or password for that email.
Security notes#
- Passwords are hashed with PBKDF2 (SHA-256, 100,000 iterations, the most a Worker allows). Session tokens are stored hashed, in an HttpOnly, Secure, SameSite=Lax cookie.
- After 10 wrong passwords for an email, or 50 from one address, sign-in is locked for 15 minutes. Requests for links, resets and sign-ups are limited per email and per address.
- Password reset gives the same answer and timing whether or not the account exists, so the form can't be used to find out who has an account.
- If someone registers an email with a password and its real owner later proves the address (magic link, Google or GitHub), the earlier password is discarded.
Errors#
Failures return JSON like { "error": "invalid_credentials" } with a matching status: invalid_email and weak_password (400), email_taken (409), invalid_credentials (401), too_many_attempts (429), disabled and email_not_verified (403), email_unavailable (503), invalid_token and oauth_failed (400).
Limits#
HostEdge Auth keeps its tables in your project database, so users count toward your storage and request allowances like any other data. It suits apps up to a few thousand concurrent users; see Databases and storage for connecting your own Postgres when you outgrow that.