Sign-in and security rules
Let people create accounts in your app and decide, in the database, what each of them may see and change.
1. Settings
In Authentication › Settings, set the Site URL to your app's address. Confirmation and password-reset emails link there. “Require email verification” can be turned off (for example while testing). Under Authentication you can also see your users, disable them, send a password reset or sign them out everywhere.
2. Sign-up and sign-in
// Sign up: Espobase sends a confirmation email that links to your Site URL.
const { error } = await espobase.auth.signUp({ email, password }); // passwords need 8+ characters
// After confirming, sign in. The session is stored and refreshed automatically.
await espobase.auth.signInWithPassword({ email, password });
const { data } = await espobase.auth.getUser(); // data.user.id, data.user.email
await espobase.auth.signOut();3. Handle email links
Confirmation and reset links open your Site URL with the token in the part after #, which never reaches a server. A few lines on that page complete the step:
// On the page your Site URL points to: email links carry the token after "#".
const params = new URLSearchParams(window.location.hash.slice(1));
const token = params.get("token");
if (token && params.get("type") === "signup") {
await espobase.auth.verifyEmail({ token }); // confirms the address and signs the user in
}
if (token && params.get("type") === "recovery") {
// Show a "new password" form, then:
await espobase.auth.resetPassword({ token, password: newPassword });
}
history.replaceState(null, "", window.location.pathname); // remove the token from the address bar// "Forgot password": sends a reset link to the Site URL (#type=recovery&token=…). await espobase.auth.resetPasswordForEmail(email);
5. Sign in without a password
Turn on Email sign-in without a password in Authentication › Settings. One email carries a sign-in link and a 6-digit code; both work once, for 10 minutes. People sign in with whichever is easier, for example the code on another device:
// Emails a sign-in link and a 6-digit code (same answer whether or not the account exists).
await espobase.auth.signInWithOtp({ email });
// The user types the code…
await espobase.auth.verifyOtp({ email, code });
// …or opens the link: your Site URL with #type=magiclink&token=…
const params = new URLSearchParams(window.location.hash.slice(1));
if (params.get("type") === "magiclink") {
await espobase.auth.verifyOtp({ token: params.get("token")! });
history.replaceState(null, "", window.location.pathname);
}6. Two-step sign-in and email change
In Authentication › Settings, two-step sign-in can be optional or required: after the first step, people enter a code from an authenticator app or from an email, or a recovery code. “Let users change their email” lets signed-in users move to a new address, confirmed by a link; the old address gets a notice.
// With two-step sign-in, a sign-in can wait for its second step:
const { error } = await espobase.auth.signInWithPassword({ email, password });
if (error?.code === "mfa_required") {
await espobase.auth.mfa.verify({ code }); // authenticator, emailed code (mfa.challenge()) or recovery code
}
// Signed in: set up an authenticator app (show data.uri as a QR code), then confirm it with a code.
const { data } = await espobase.auth.mfa.enroll({ type: "totp" });
const { data: done } = await espobase.auth.mfa.verifyEnrollment({ factorId: data!.factorId, code });
// done.recoveryCodes: show them once
// Change the email address (confirmed by a link to the new address: #type=email_change&token=…)
await espobase.auth.updateUser({ email: newEmail, currentPassword });
await espobase.auth.verifyEmailChange({ token });7. Security rules (row level security)
Row level security is on for every table: until you add a policy, nobody can read or write it through the API. In a policy, espobase.user_id() is the signed-in user's id (empty for visitors who aren't signed in).
-- Each user sees and changes only their own rows: create policy "Own notes" on notes for all using (owner_id = espobase.user_id()) with check (owner_id = espobase.user_id()); -- Everyone may read published posts; only signed-in users may write: create policy "Read published posts" on posts for select using (published); create policy "Signed-in users post" on posts for insert with check (espobase.user_id() is not null);
In the dashboard, Database › Policies offers the same as templates (Public read, Authenticated only, User owns row, Organization membership) and shows the SQL before it's applied.
8. Which key where
- Publishable key (
eb_pk_…): in your app and the browser. Every request runs as the signed-in user (or as a visitor), so your policies decide. - Secret key (
eb_sk_…): only on your own server, for jobs such as webhooks. It bypasses the policies, so never ship it to a browser.
4. Sign in with Google or GitHub
Turn the provider on in Authentication › Providers: create an OAuth app at Google or GitHub, register the Callback URL shown there, and enter the app's client ID and client secret. The secret is stored encrypted and never shown again. Then one call sends people to the provider; they come back to your Site URL (or an allowed redirect URL) with
?code=…:// Sends the browser to Google; afterwards it comes back with ?code=… (or ?error=…). await espobase.auth.signInWithOAuth({ provider: "google" }); // or "github" // On the page it comes back to (your Site URL, or options.redirectTo): const params = new URL(window.location.href).searchParams; const code = params.get("code"); if (code) { const { error } = await espobase.auth.exchangeCodeForSession(code); // signs the user in history.replaceState(null, "", window.location.pathname); }Only a provider-verified email is accepted. It joins an existing account only when that account's email is confirmed too. If the sign-in can't finish, the URL carries
?error=…(for exampleaccess_deniedoraccount_exists) and anerror_descriptionto show.