Auth
Built-in authentication with JWT tokens. Sign up, sign in, refresh, and sign out — all via REST. Every response uses the same { data: ... } envelope as the rest of the API.
Roles
The first account created on a project becomes its owner; everyone who signs up after is a member. Only the owner can reach /admin/* — creating tables, changing a table's access policy, running typegen. A member who tries gets 403 FORBIDDEN.
Close signup once your owner account exists by setting signupEnabled to false in the project's /srv/based/projects/<name>/config.json. POST /auth/signup then answers 403 SIGNUP_DISABLED. It defaults to true.
POST /auth/signup
Create a new account. Returns the user and a token pair.
curl -X POST https://my-app.based.yourdomain.com/auth/signup \
-H "Content-Type: application/json" \
-d '{ "email": "user@example.com", "password": "secret123" }'{
"data": {
"user": {
"id": "V1StGXR8_Z5jdHi6B",
"email": "user@example.com",
"role": "owner"
},
"accessToken": "eyJhbG...",
"refreshToken": "eyJhbG..."
}
}POST /auth/signin
Sign in with existing credentials. Returns the user and a token pair.
curl -X POST https://my-app.based.yourdomain.com/auth/signin \
-H "Content-Type: application/json" \
-d '{ "email": "user@example.com", "password": "secret123" }'{
"data": {
"user": {
"id": "V1StGXR8_Z5jdHi6B",
"email": "user@example.com",
"role": "member"
},
"accessToken": "eyJhbG...",
"refreshToken": "eyJhbG..."
}
}POST /auth/refresh
Exchange a refresh token for a new pair. The old session is deleted, so a refresh token is single-use — never run two refreshes in parallel, or the loser signs the user out.
curl -X POST https://my-app.based.yourdomain.com/auth/refresh \
-H "Content-Type: application/json" \
-d '{ "refreshToken": "eyJhbG..." }'{
"data": {
"accessToken": "eyJhbG...",
"refreshToken": "eyJhbG..."
}
}GET /auth/me
Return the authenticated user's profile — no client-side JWT decoding required. Requires a Bearer token (anon key is rejected).
curl https://my-app.based.yourdomain.com/auth/me \
-H "Authorization: Bearer eyJhbG..."{
"data": {
"id": "V1StGXR8_Z5jdHi6B",
"email": "user@example.com",
"role": "owner",
"createdAt": "2026-09-09T10:00:00.000Z"
}
}POST /auth/signout
Deletes the caller's sessions, so every refresh token they hold stops working. Requires a valid Bearer token.
curl -X POST https://my-app.based.yourdomain.com/auth/signout \
-H "Authorization: Bearer eyJhbG..."Auth middleware
Protected endpoints require a Bearer token in the Authorization header.
Authorization: Bearer <accessToken>For anonymous access, pass your project anon key in the apikey header instead. An anon caller can only read tables whose access policy is public-read.
apikey: <anonKey>Token lifetimes
| Token | Expires | Stored |
|---|---|---|
| Access token | 1 hour | Client side only — never persisted server side |
| Refresh token | 7 days | Hashed in the sessions table; rotated on every refresh |
The SDK keeps both in localStorage by default so a session survives a reload. That makes them readable by any script on your origin — an XSS bug leaks the session. Pass a custom storage adapter, or storage: false, if that tradeoff is wrong for you.