Authentication & Login
Overview
Section titled “Overview”Rebase provides ready-to-use React components and hooks for authentication:
useRebaseAuthController— Manages auth state, tokens, and session persistenceLoginView— Pre-built login/signup form with OAuth support- Role simulation — Test different roles without logging out
Auth Controller
Section titled “Auth Controller”The useRebaseAuthController hook is the core of frontend authentication. It manages the current user, tokens, and session:
import { useRebaseAuthController } from "@rebasepro/app";import { createRebaseClient } from "@rebasepro/client";
const client = createRebaseClient({ baseUrl: API_URL, websocketUrl: WS_URL });
const authController = useRebaseAuthController({ client, googleClientId: GOOGLE_CLIENT_ID // Optional — enables Google OAuth});
// Available properties:authController.user // Current user object (or null)authController.initialLoading // True while checking stored sessionauthController.signOut() // Log outauthController.getAuthToken() // Get current JWT for API callsPass the authController to <Rebase authController>. <RebaseShell> (or <RebaseAuthGate> in a manual layout) reads it from there and gates the entire admin panel behind authentication.
Your Own Auth Provider
Section titled “Your Own Auth Provider”On 0.24 the getter authenticates HTTP requests only, and the panel’s realtime socket stays anonymous.
If your app signs users in with its own provider (Clerk, Firebase Auth, a
session of its own), give the client you pass to <Rebase client> a token
getter. The panel’s HTTP requests and its realtime socket both send what it
returns, so live collection views run as the same user:
client.setAuthTokenGetter(() => clerk.session?.getToken() ?? Promise.resolve(null));The authController beside it then reports your provider’s signed-in user
(an AuthController from @rebasepro/cms-types) instead of wrapping
client.auth. The backend has to accept the token too: see
Custom auth adapters, and
Your Own Auth Provider
for the client side in full.
Login View
Section titled “Login View”The LoginView component provides a complete login and registration form:
import { LoginView } from "@rebasepro/app";
function App() { if (!authController.user) { return ( <LoginView authController={authController} googleClientId={GOOGLE_CLIENT_ID} /> ); } return <MyApp />;}The login view handles:
- Email/password login and registration
- Google, GitHub and LinkedIn OAuth sign-in (when configured)
- Password reset flow
- Form validation and error states
Roles Model
Section titled “Roles Model”Roles are stored as a text[] array column directly on the rebase.users table. You define available roles as an enum in your users collection definition:
roles: { name: "Roles", type: "array", columnType: "text[]", of: { name: "Role", type: "string", enum: { admin: "Admin", editor: "Editor", viewer: "Viewer" } }, admin: { readOnly: false }}To add or remove role options, update the enum map in your users collection and regenerate the schema.
A role in this list is a name your security rules can match. What it may do beyond its rows (manage users, read logs, change the schema) is declared separately, under auth.roles on the same collection. admin is built in and holds everything. See Roles and scopes.
Testing access: Simulate access
Section titled “Testing access: Simulate access”To check what a role, a user or a service key can read, an administrator uses Simulate access, the pill above your avatar in the admin panel’s drawer (in the app bar on a small screen, or when the shell has no drawer). Pick a role (with an optional user id, which need not be an account), a user, or a live service key. Every data view, and a record’s History tab, then reads through the server as that identity, against the real row-level security policies: a grid shows exactly the rows it can read, fields its roles cannot read are masked, and the banner counts the collections it sees nothing in. The server checks on every request that you are an administrator.
Simulated access is read-only. While it is on, the views offer no create, edit,
delete or history revert, and the server refuses any write that carries a simulation with
403 SIMULATION_READ_ONLY, so nothing is saved as someone else. Stop simulating
to make changes.
What it does not simulate: the data API’s requireAuth gate, which lets a
simulated anonymous caller past so you see what the rows’ policies give it
(a custom function sees it as no session, as a real anonymous caller is);
storage, whose files are read as you, with uploads off while simulating; and
live updates, which pause until you stop.
The same thing from code, on the SDK, is client.simulate(). It derives a
client whose requests carry the simulation, and only an administrator’s own
session may use it:
const asCustomer = client.simulate({ role: "customer", userId: "u_1" });const { data } = await asCustomer.data.collection("tickets").find();asCustomer.close();The derived client is typed by the same Database as the one it came from, and
is a client of its own: close() it when you are done.
The effective-role switch is not an RLS tester: it only changes which Studio
views the navigation lists, sends nothing to the server, and evaluates no
policy. useBuildEffectiveRoleController, which built one, is deprecated and
warns once when called: <Rebase> builds its own controller when none is
passed, and Simulate access is the way to test what a role can do.
Next Steps
Section titled “Next Steps”- Backend Authentication — JWT, OAuth providers, SMTP configuration
- Security Rules (RLS) — Row-level access control per collection
- Typed SDK Authentication — Programmatic auth methods