Guides

Auth

Native Robodev Auth on each project host: email/password now, Google when configured, and defineApi auth.

Each deployed project host has Robodev Auth. End users sign up and log in on that host. This is not the Starbase dashboard or CLI login, and it does not reuse control-plane JWTs. Dashboard Google sign-in, password reset, and Profile on /login and /profile are control-plane only and do not change project-host Auth users. Organization members configure providers and see signed-up users on the project Auth page (/projects/:id/auth).

Access tokens are Bearer JWTs (15 minutes, typ project_access). Refresh tokens last 30 days and rotate on use. Store both and send Authorization: Bearer <accessToken>. There are no auth cookies. Sign-out revokes the refresh token.

Reserved routes

These Tiny /api/user/* paths are reserved on every project host. A file at api/user.ts or api/user/** is not registered.

  • POST /api/user/auth/login — body { email, password } → { accessToken, refreshToken }. 401 invalid-credentials.
  • POST /api/user/auth/register — body { email, password, name? }, password min 12 → 201 tokens. 409 identity-already-exists.
  • POST /api/user/auth/refresh — body { refreshToken } → new token pair. Reuse → 401 identity-not-found.
  • GET /api/user/auth/magic-link?email= — 200 generic StatusResponse. Optional redirect_uri (same rules as Google). Email links to {app}?type=magic&code=.
  • GET /api/user/auth/magic-link/callback?code= — 200 tokens, or 400 nonce-invalid.
  • POST /api/user/auth/forgot-password — body { email } → 200 generic StatusResponse. Email includes the code and {projectPublicUrl}?type=forgot-password&code=.
  • POST /api/user/auth/forgot-password/callback — body { code, password } min 12 → 200 Password updated. No tokens.
  • GET /api/user/auth/google?redirect_uri= — 302 to Google. After success the app redirect gets query accessToken and refreshToken.
  • GET /api/user/me — Bearer required → { id, name, email }.
  • PUT /api/user/me — Bearer body { name?, email? } → updated profile.
  • GET /api/user/auth/apple/callback — 503 not_implemented.

Errors use top-level code and message (invalid-credentials, identity-already-exists, identity-not-found, nonce-invalid, invalid-request). Users live in the tenant schema robodev_auth, not in your app tables. Register welcome, magic-link, and forgot-password mail go through the project's SMTP and appear on the Email page.

defineApi auth

  • false (default) — public. Existing APIs stay public.
  • "required" — missing or invalid Bearer → 401, handler not called. ctx.user is the project user.
  • "optional" — invalid token becomes user: null; the handler still runs.
  • custom verifier — async ({ headers }) => AuthUser | null. Null → 401.
  • "schedule" — 401 unless the request has a valid x-robodev-schedule HMAC. See Schedules (/docs/schedules).

api/me.ts

import { defineApi, z } from "@robodev-ai/sdk";
export const get = defineApi({
auth: "required",
handler: async ({ user }) => ({ user }),
});

@robodev-ai/client

Browser helper. No React hooks in this package. Tokens are stored under robodev:{url}:accessToken and robodev:{url}:refreshToken. api.fetch refreshes once on 401 and retries.

browser

import { createClient } from "@robodev-ai/client";
const api = createClient({ url: import.meta.env.VITE_API_URL });
await api.auth.signUp({ email, password, name });
await api.auth.signIn.email({ email, password });
const { user } = await api.auth.getUser();
api.auth.signIn.google(); // redirect; then api.consumeTokenFromUrl()
await api.auth.refresh();
await api.auth.signOut();
const me = await api.fetch("/api/me").then((r) => r.json());

signUp and signIn.email return { accessToken, refreshToken }. getUser wraps flat GET /api/user/me as { user }. consumeTokenFromUrl reads query accessToken and refreshToken after Google redirect, then strips them with replaceState.

Google

On by default per project (Robodev mode). On the dashboard Auth page, you can switch to Off or Custom (your Google client id and secret). Platform env is GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, and PUBLIC_URL — those keys are still required for Robodev Google. Authorized redirect URI is always {PUBLIC_URL}/internal/auth/google/callback. Start Google from GET /api/user/auth/google?redirect_uri=. After success the browser returns to redirect_uri with query accessToken and refreshToken. redirect_uri must be https, or http on localhost / 127.0.0.1 / [::1].

  • Auth off → reserved /api/user/** return 404 auth_disabled.
  • Email/password off → login, register, magic-link, and forgot-password return 403 email_password_disabled.
  • Allow signups off → register 403 signup_disabled; existing users can still log in. New Google emails redirect with error=signup_disabled.
  • OAuth off → /api/user/auth/google 503 google_oauth_disabled.
  • OAuth on but keys missing → 503 google_oauth_unconfigured.

Custom auth

A header verifier that returns the same AuthUser shape is supported. Cookie or redirect flows you build yourself are out of scope for this ship.