Sign-in and sessions
app.auth drives an authored sign-in screen. usePlatformSession and SignInGate give exported and self-hosted apps the same sign-in the platform runs, against /__appbricx/auth.
On this page
- app.auth
- app.auth.mode
- app.auth.setMode
- app.auth.canSignUp
- app.auth.signIn
- app.auth.signUp
- app.auth.requestReset
- app.auth.providers
- app.auth.startProvider
- app.auth.skip
- app.auth.signOut
- usePlatformSession
- usePlatformSession
- usePlatformSession().session
- usePlatformSession().signIn
- usePlatformSession().signUp
- usePlatformSession().signOut
- usePlatformSession().requestReset
- usePlatformSession().startProvider
- usePlatformSession().discovery
- SignInGate
- SignInGate
- Types
On a sign-in screen you author (spec.auth.screen) every app.auth verb works. Inside the signed-in app only signOut does; the others reject with "<verb> is only available on the sign-in screen".
Sessions are an HttpOnly cookie (appbricx_app_session) on the app's own origin. Cross-origin apps fall back to a token kept in localStorage and sent as x-appbricx-app-session.
app.auth
app.auth.modeproperty
Which form the sign-in screen shows: "login", "signup" or "forgot".
app.auth.mode: "login" | "signup" | "forgot"- Returns
- The current mode. Starts at "login".
- Errors
- Does not throw.
- Permissions
- Local UI state.
if (app.auth.mode === "forgot") return <ResetForm app={app} />;Source: packages/appkit/src/kits/primitives/app-handle.ts:50
app.auth.setModemethod
Switch the sign-in screen's form. Switching to "signup" is ignored when public sign-up is closed.
app.auth.setMode(mode: "login" | "signup" | "forgot"): voidParameters
| Name | Type | Description |
|---|---|---|
moderequired | "login" | "signup" | "forgot" | "login", "signup" or "forgot". |
- Returns
- Nothing.
- Errors
- Does not throw.
- Permissions
- Local UI state; the signup policy is enforced server-side as well.
<button onClick={() => app.auth.setMode("signup")}>Create an account</button>Source: packages/appkit/src/kits/primitives/app-handle.ts:51
app.auth.canSignUpproperty
True when the app's signup policy is "open". Hide the sign-up link otherwise.
app.auth.canSignUp: boolean- Returns
- boolean, from GET /__appbricx/auth/signup-options.
- Errors
- Does not throw.
- Permissions
- The server refuses sign-ups on invite-only and closed apps whatever the screen shows.
{app.auth.canSignUp && <a onClick={() => app.auth.setMode("signup")}>Sign up</a>}Source: packages/appkit/src/kits/primitives/app-handle.ts:53
app.auth.signInmethod
Sign in with email and password. On success the app session cookie is set and the screen gives way to the app.
app.auth.signIn(email: string, password: string): Promise<void>Parameters
| Name | Type | Description |
|---|---|---|
emailrequired | string | The account's email. |
passwordrequired | string | Its password. |
- Returns
- Resolves when signed in.
- Errors
- "INVALID_CREDENTIALS" for a wrong email or password, "ACCOUNT_DISABLED" for a disabled account (the server's error code is the message).
- "Sign in failed — check the email and password." when no session came back, which includes accounts with two-factor sign-in enabled (use the platform screen or POST /__appbricx/auth/mfa/verify).
- Inside the signed-in app: "signIn is only available on the sign-in screen".
- Permissions
- Public. Rate limited per IP by the auth routes.
async function onSubmit(e: FormEvent) {
e.preventDefault();
try {
await app.auth.signIn(email, password);
} catch (err) {
setError(err instanceof Error ? err.message : "Sign in failed");
}
}Source: packages/appkit/src/kits/primitives/app-handle.ts:54
app.auth.signUpmethod
Create an account and sign in. When the server answers without a session (pending verification, or the email already exists) it completes with a sign-in.
app.auth.signUp(fields: { name: string; email: string; password: string }): Promise<void>Parameters
| Name | Type | Description |
|---|---|---|
fieldsrequired | { name: string; email: string; password: string } | { name, email, password }. The password needs at least 8 characters. |
- Returns
- Resolves when signed in.
- Errors
- "Password must be at least 8 characters." (WEAK_PASSWORD), "INVALID_EMAIL".
- "Sign-ups are closed for this app." (SIGNUP_DISABLED) or "This app is invite-only. Ask an administrator for an invitation." (SIGNUP_INVITE_ONLY).
- Any sign-in error when the follow-up sign-in fails.
- Permissions
- Public when the signup policy is open. The new account gets the app's self-signup persona.
await app.auth.signUp({ name, email, password });Source: packages/appkit/src/kits/primitives/app-handle.ts:55
app.auth.requestResetmethod
Email a password-reset link. The answer is the same whether or not the account exists (no account enumeration).
app.auth.requestReset(email: string): Promise<void>Parameters
| Name | Type | Description |
|---|---|---|
emailrequired | string | The address to send the link to. |
- Returns
- Resolves once the request is accepted.
- Errors
- "Enter a valid email address." for a malformed address. Nothing else is reported.
- Permissions
- Public. Mail-request rate limits apply.
await app.auth.requestReset(email);
setNotice("If that address has an account, a reset link is on its way.");Source: packages/appkit/src/kits/primitives/app-handle.ts:56
app.auth.providersproperty
The social sign-in providers turned on for this app (Google, GitHub), in order. Render a "Continue with {label}" button for each.
app.auth.providers: Array<{ name: string; label: string }>- Returns
- Array<{ name, label }>, from GET /__appbricx/auth/oauth/providers. Empty when none are on.
- Errors
- Does not throw.
- Permissions
- Public discovery.
{app.auth.providers.map((p) => (
<button key={p.name} onClick={() => app.auth.startProvider(p.name)}>
Continue with {p.label}
</button>
))}Source: packages/appkit/src/kits/primitives/app-handle.ts:59
app.auth.startProvidermethod
Leave for the provider's sign-in page. The user comes back to this exact page signed in.
app.auth.startProvider(name: string): Promise<void>Parameters
| Name | Type | Description |
|---|---|---|
namerequired | string | A provider name from app.auth.providers, e.g. "google". |
- Returns
- Never resolves in practice: the page navigates away.
- Errors
- "Sign-in with this provider isn't available on this address." when the page's origin isn't one of the app's hosts (ORIGIN_NOT_ALLOWED).
- "That sign-in option isn't available right now." when the provider isn't configured.
- Permissions
- Public. The OAuth state is signed and single-use.
<button onClick={() => app.auth.startProvider("google")}>Continue with Google</button>Source: packages/appkit/src/kits/primitives/app-handle.ts:61
app.auth.skipmethodmay be undefined
Continue without signing in, when the app allows browsing. Undefined on apps that start on a public landing page.
app.auth.skip(): void- Returns
- Nothing.
- Errors
- Does not throw.
- Permissions
- The visitor becomes a guest: row-level security shows exactly what an anonymous caller may see.
{app.auth.skip && <button onClick={app.auth.skip}>Browse without an account</button>}Source: packages/appkit/src/kits/primitives/app-handle.ts:63
app.auth.signOutmethod
Sign out: clears the session cookie on the server and the remembered profile. Works everywhere, not only on the sign-in screen.
app.auth.signOut(): void- Returns
- Nothing; the request is fire-and-forget.
- Errors
- Does not throw.
- Permissions
- Acts on the current session only.
<button onClick={() => app.auth.signOut()}>Sign out</button>Source: packages/appkit/src/kits/primitives/app-handle.ts:64
usePlatformSession
usePlatformSessionfunction
The sign-in state of a compiled or exported app against /__appbricx/auth. Owns login, signup, logout, reset and social sign-in, persists the profile, and fetches what the sign-in screen may offer.
usePlatformSession(opts: { … }): { session, signIn, signUp, signOut, requestReset, startProvider, discovery }Parameters
| Name | Type | Description |
|---|---|---|
opts.apiBaserequired | string | The platform origin that serves /__appbricx ("" for the app's own origin). |
opts.projectTokenrequired | string | The app's public data token (dpk_c_…) or preview token; sent as Authorization: Bearer. |
opts.envoptional | "dev" | "prod" | "dev" or "prod". Default: inferred from the URL, the same default the data runtime uses, so sign-in and data hit the same database. |
- Returns
- { session, signIn, signUp, signOut, requestReset, startProvider, discovery }.
- Errors
- Does not throw.
- Permissions
- Same-origin apps keep the token in the HttpOnly cookie and only the profile in localStorage; cross-origin apps keep the token in localStorage.
const auth = usePlatformSession({ apiBase: "", projectToken: import.meta.env.VITE_APPBRICX_TOKEN });
if (!auth.session) return <LoginForm onSubmit={auth.signIn} />;Source: packages/appkit/src/kits/platform-auth.tsx:64
usePlatformSession().sessionproperty
The current session: { token?, userId?, email, name, role? }, or null signed out. On a same-origin app it is confirmed against GET /__appbricx/auth/me once per load.
const { session } = usePlatformSession(opts)- Returns
- PlatformSession | null.
- Errors
- Does not throw.
- Permissions
- The token is in memory only (cookie mode) or in localStorage (cross-origin).
const { session } = usePlatformSession(opts);
return session ? <p>Signed in as {session.email}</p> : null;Source: packages/appkit/src/kits/platform-auth.tsx:64
usePlatformSession().signInmethod
POST /__appbricx/auth/login and store the session.
const { signIn } = usePlatformSession(opts)- Returns
- Promise<void>.
- Errors
- The server's error code (INVALID_CREDENTIALS, ACCOUNT_DISABLED), or "Sign in failed — check the email and password." when no token came back (including two-factor accounts).
- Permissions
- Public.
const { signIn } = usePlatformSession(opts);
await signIn("ada@example.com", "correct horse battery");Source: packages/appkit/src/kits/platform-auth.tsx:64
usePlatformSession().signUpmethod
POST /__appbricx/auth/signup with { name, email, password, persona? }, then sign in (directly when a token comes back, else by password).
const { signUp } = usePlatformSession(opts)- Returns
- Promise<void>.
- Errors
- The server's message or code: WEAK_PASSWORD, INVALID_EMAIL, SIGNUP_DISABLED, SIGNUP_INVITE_ONLY.
- Permissions
- Public when the signup policy is open. persona must be one of discovery.signupPersonas.
await signUp({ name: "Ada", email, password, persona: "customer" });Source: packages/appkit/src/kits/platform-auth.tsx:64
usePlatformSession().signOutmethod
POST /__appbricx/auth/logout (clears the cookie server-side) and drop the session.
const { signOut } = usePlatformSession(opts)- Returns
- void.
- Errors
- Does not throw.
- Permissions
- Current session only.
<button onClick={signOut}>Sign out</button>Source: packages/appkit/src/kits/platform-auth.tsx:64
usePlatformSession().requestResetmethod
POST /__appbricx/auth/reset/request. Constant response by design.
const { requestReset } = usePlatformSession(opts)- Returns
- Promise<void>.
- Errors
- "Enter a valid email address." on INVALID_EMAIL.
- Permissions
- Public.
await requestReset(email);Source: packages/appkit/src/kits/platform-auth.tsx:64
usePlatformSession().startProvidermethod
Start social sign-in: asks /__appbricx/auth/oauth/:name/start?json=1 for the provider URL and navigates there, returning to the current page.
const { startProvider } = usePlatformSession(opts)- Returns
- Promise<void> (the page navigates away).
- Errors
- "Sign-in with this provider isn't available on this address." or "That sign-in option isn't available right now."
- Permissions
- Public.
await startProvider("github");Source: packages/appkit/src/kits/platform-auth.tsx:64
usePlatformSession().discoveryproperty
What the sign-in screen may offer: configured providers, the signup policy ("open", "invite_only" or "disabled") and the personas a visitor may pick at sign-up. A failed fetch means none.
const { discovery } = usePlatformSession(opts)- Returns
- AuthDiscovery.
- Errors
- Does not throw.
- Permissions
- Public discovery.
const { discovery } = usePlatformSession(opts);
const canSignUp = discovery.signupPolicy === "open";Source: packages/appkit/src/kits/platform-auth.tsx:64
SignInGate
SignInGatecomponent
Renders the app's sign-in surface until a session exists, then the app. Visitors may continue signed out when the app allows it. With landing, guests see the public landing page first and the sign-in screens open on request. An authored screen replaces the platform's, and if it throws the platform screen takes over.
<SignInGate {...props} />Parameters
| Name | Type | Description |
|---|---|---|
props.sessionrequired | PlatformSession | null | The current session (from usePlatformSession), or null. |
props.signInrequired | (email: string, password: string) => Promise<void> | Sign-in function, usually usePlatformSession().signIn. |
props.signUprequired | (fields: { name: string; email: string; password: string; persona?: string }) => Promise<void> | Sign-up function, usually usePlatformSession().signUp. |
props.skippedrequired | boolean | True after the visitor chose to continue signed out. The caller owns it so sign-out can bring the gate back. |
props.onSkiprequired | () => void | Called when the visitor continues signed out. |
props.brandNamerequired | string | The app's name on the sign-in screen. |
props.brandIconoptional | string | Icon name for the brand mark. |
props.taglineoptional | string | One line under the brand. |
props.authSpecoptional | Partial<AuthPagesProps> | The contract's auth page settings (layout, copy). |
props.landingoptional | boolean | The app has a public landing page at "/": guests start there. |
props.personasoptional | Array<{ id: string; label: string; description?: string }> | The app's personas, used to label the sign-up persona picker. |
props.discoveryoptional | AuthDiscovery | usePlatformSession().discovery: providers, signup policy, sign-up personas. |
props.requestResetoptional | (email: string) => Promise<void> | Forgot-password function. |
props.startProvideroptional | (name: string) => Promise<void> | Social sign-in function. |
props.screenoptional | React.ComponentType<Record<string, unknown>> | null | An authored sign-in component (spec.auth.screen). It receives app with every app.auth verb. |
props.childrenrequired | React.ReactNode | The signed-in app. |
- Returns
- React element.
- Errors
- Does not throw.
- Permissions
- Signed-out visitors browse as guests: row-level security decides what they see. Signup is offered only when the policy is open.
const auth = usePlatformSession({ apiBase: "", projectToken });
const [skipped, setSkipped] = useState(false);
return (
<SignInGate session={auth.session} signIn={auth.signIn} signUp={auth.signUp}
skipped={skipped} onSkip={() => setSkipped(true)} brandName="Tablefor"
discovery={auth.discovery} requestReset={auth.requestReset} startProvider={auth.startProvider}>
<App />
</SignInGate>
);Source: packages/appkit/src/kits/platform-auth.tsx:233
Types
type PlatformSession = {
token?: string;
userId?: string;
email: string;
name: string;
role?: string;
}Source: packages/appkit/src/kits/platform-auth.tsx:34
type AuthDiscovery = {
providers: Array<{
name: string;
label: string;
}>;
signupPolicy: "open" | "invite_only" | "disabled";
signupPersonas: string[];
}Source: packages/appkit/src/kits/platform-auth.tsx:44