Authentication overview
Every project has its own user directory. Your app’s users sign up and sign in against your project (the routes live under /projects/{projectId}/auth/...), and each successful sign-in returns an access token that identifies the user to the data API, storage, functions and realtime.
This page is about your app’s users. Signing in to the VAIF Studio console itself, including with your company’s identity provider, is covered in Single sign-on.
What is available
Section titled “What is available”| Method | Status |
|---|---|
| Email and password | Available |
| Magic links (passwordless email) | Available |
| Two-factor sign-in with an authenticator app (TOTP) and backup codes | Available |
| Password reset and email verification | Available |
| Device sessions (list and revoke) | Available |
| Social sign-in | Available. See Social sign-in |
Sign up and sign in
Section titled “Sign up and sign in”Create the client with your project ID and publishable key:
import { createVaifClient } from "@vaifstudio/client";
let accessToken = "";
const vaif = createVaifClient({ baseUrl: "https://api.vaif.studio", projectId: process.env.VAIF_PROJECT_ID, apiKey: process.env.VAIF_PUBLISHABLE_KEY, accessToken: () => accessToken,});
await vaif.auth.signUp("sam@example.com", "a-long-unique-passphrase");
const result = await vaif.auth.login("sam@example.com", "a-long-unique-passphrase");
if ("challengeToken" in result) { // The user has two-factor sign-in on: ask for the 6-digit code, then finish signing in. const session = await vaif.auth.mfa.verify(result.challengeToken, "123456"); accessToken = session.accessToken;} else if ("accessToken" in result) { accessToken = result.accessToken;}
const me = await vaif.auth.getUser();console.log(me.email);
await vaif.auth.logout();The SDK does not store the token. Keep it (in memory, or wherever your app keeps secrets) and hand it back through accessToken, as above, so every request carries it.
Magic links
Section titled “Magic links”await vaif.auth.magic.send("sam@example.com", { redirectUrl: "https://app.example.com/auth/callback",});The email’s link signs the user in and redirects to redirectUrl with the token in the URL fragment: #access_token=…, or #mfa_challenge=… when the user has two-factor sign-in on. Read it on your callback page:
const params = new URLSearchParams(window.location.hash.slice(1));const token = params.get("access_token");const challenge = params.get("mfa_challenge");
if (challenge) { const session = await vaif.auth.mfa.verify(challenge, "123456"); console.log(session.accessToken);} else if (token) { console.log("signed in", token.length > 0);}The redirect URL’s origin must be on your project’s allowed redirect URLs (Authentication > URL configuration in the console).
Two-factor sign-in
Section titled “Two-factor sign-in”Two-factor sign-in is allowed when Allow two-factor sign-in is on under Authentication > Multi-factor. Users then turn it on for themselves in two steps:
// 1. Start: show a QR code for otpauthUri (or the secret for manual entry).const { otpauthUri, secret, enrollToken } = await vaif.auth.mfa.enrollStart();console.log(otpauthUri, secret);
// 2. Confirm with the first code from their app. Show the backup codes once.const { backupCodes } = await vaif.auth.mfa.enrollConfirm(enrollToken, "123456");console.log(backupCodes);After that, login() answers { mfaRequired: true, challengeToken } and the user finishes with vaif.auth.mfa.verify(challengeToken, code). A backup code works in place of a code. vaif.auth.mfa.disable(code) turns two-factor sign-in off, and vaif.auth.mfa.regenerateCodes(code) issues new backup codes.
Password reset and email verification
Section titled “Password reset and email verification”await vaif.auth.requestPasswordReset({ email: "sam@example.com", redirectUrl: "https://app.example.com/reset" });
// On the reset page, with the token from the link:await vaif.auth.confirmPasswordReset({ token: "token-from-the-link", password: "a-new-passphrase" });
await vaif.auth.requestEmailVerification({ redirectUrl: "https://app.example.com/verified" });await vaif.auth.confirmEmailVerification({ token: "token-from-the-link" });Mirror users into a table
Section titled “Mirror users into a table”User table sync is on by default: every project copies each of its users into a users table in the project (id, email, phone, provider, metadata, last_sign_in_at, created_at, updated_at), so you can query and join users with the data API. The table is created at the first sign-up, with a row rule under which each signed-in user sees only their own row. A user’s row is written when they sign up and updated each time they sign in.
To copy users who existed before the table did, call POST /projects/{projectId}/auth/sync-users once as a project admin. To sync into a table with another name, use Sync users to a table on the Authentication users page.
To turn sync off, set userTableName to null with PATCH /projects/{projectId}/auth/settings, as a project admin with a console access token:
curl -X PATCH https://api.vaif.studio/projects/$PROJECT_ID/auth/settings \ -H "Authorization: Bearer $VAIF_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "userTableName": null }'Users then stop being copied. A table that already exists, and its rows, stay until you remove them.
Next steps
Section titled “Next steps”- Session management: token lifetime and device sessions
- Row rules: limit each user to their own rows
- API keys: publishable and secret keys