Plexivo Auth
Sign users up and in with a password, an email code, Google, GitHub or Microsoft, stored in your own Plexivo Postgres database.
Plexivo Auth signs your app’s users up and in, and keeps them in your own Plexivo Postgres database. Once a user signs in, every Data API, Realtime and GraphQL request runs as them, and your row-level security policies see their id as auth.uid().
Turn on sign-in#
- Turn on the Data API on the database’s Connect tab, if you have not already. See Data API.
- Open Authentication. Email and password, Email one-time code and Password recovery email are on from the start; the Providers view shows each method’s status.
- Open Sign-in methods to turn on Google, GitHub or Microsoft under Social sign-in, and Guests if you want them.
- Add your Return URLs: where your app may be sent back to after a social sign-in.
- Choose Save sign-in methods.
Sign up and sign in#
import { createClient } from '@plexivo/client';
const db = createClient(PLEXIVO_DATA_URL, PLEXIVO_PUBLISHABLE_KEY);
await db.auth.signUp({ email, password });
await db.auth.signInWithPassword({ email, password });
// Sign in with an emailed code, no password
await db.auth.signInWithOtp({ email });
await db.auth.verifyOtp({ email, token: code });
// Forgotten password
await db.auth.resetPasswordForEmail(email);
await db.auth.verifyPasswordRecovery({ email, code, newPassword });
db.auth.onAuthStateChange((event, session) => render(session?.user));
await db.auth.signOut();final db = PlexivoClient(dataUrl, publishableKey);
await db.signUp(email: email, password: password);
await db.signInWithPassword(email: email, password: password);
await db.signInWithOtp(email);
await db.verifyOtp(email: email, token: code);
await db.resetPasswordForEmail(email);
await db.verifyPasswordRecovery(email: email, code: code, newPassword: newPassword);
db.authStateChanges.listen((state) => render(state));
await db.signOut();- Passwords are 10 to 128 characters.
- Email codes are 8 digits, valid for 10 minutes, with 5 tries. Asking for a new code replaces the old one.
- A new account is signed in straight away.
Google, GitHub and Microsoft#
Social sign-in uses your own OAuth app with each provider, so users see your app’s name.
- Create an OAuth app with the provider and register the redirect URI that the console shows under Social sign-in. It looks like
https://…/client/v1/<project>/auth/oauth/callback. - Paste its Client ID and Client secret under Social sign-in and turn the provider on. The secret is stored and never shown again.
- Add your app’s address to Return URLs: an exact
httpsaddress,http://localhostwhile you build, a path ending in*to allow everything below it, or your mobile app’s own scheme such asmyapp://auth. Up to 20.
// Sends the user to the provider, then back to redirectTo with a code
await db.auth.signInWithOAuth({ provider: 'google', redirectTo: 'https://shop.example.in/auth/done' });
// On the page you returned to
await db.auth.exchangeCodeForSession(new URL(location.href).searchParams.get('code'));final url = db.getOAuthSignInUrl(provider: 'github', redirectTo: 'myapp://auth');
// Open url in the browser; when the app opens again with ?code=…
await db.exchangeCodeForSession(code);Sign-in uses PKCE. If a provider says the email address is verified, the user joins the account that already has it.
Guests#
Turn on Guests under Sign-in methods to let people use your app before they sign up. A guest has a real user id, so their rows are theirs. When they add an email and password, they keep the same id and every row.
await db.auth.signInAnonymously();
// later
await db.auth.linkEmail({ email, password });Two-step verification#
Users can add an authenticator app. After that, signing in also asks for its code.
const factor = await db.auth.mfa.enroll(); // show factor’s QR code or secret
await db.auth.mfa.verify({ code });final factor = await db.mfa.enroll();
await db.mfa.verify(code);Sessions#
- An access token lasts one hour. The client libraries refresh it for you.
- A refresh token lasts 30 days and works once: each refresh issues a new one.
- Each signed-in device is a session. Users can list theirs and end any of them; signing out with
{ scope: 'global' }ends them all. - Disabling a user or ending a session takes effect on their very next request.
In a browser, sessions are kept in localStorage. In React Native and Flutter, keep them in encrypted device storage.
Organisations#
For team apps, users can create organisations and invite others by their email address as admin or member; an owner can make another member an owner. Invitations last 7 days. Policies check membership with auth.is_org_member(org) and auth.has_org_role(org, 'admin').
const team = await db.orgs.create({ name: 'Acme' });
const invite = await db.orgs.invite(team.id, { email: 'ben@acme.in', role: 'member' });
// Send invite.token to Ben; in his app:
await db.orgs.acceptInvitation(invite.token);Users in your database#
Users live in your database, in the plexivo_auth schema. Your app’s requests cannot read it; use auth.uid() and auth.email() in your own tables and policies. Keep profile data in a table of your own, keyed by the user’s id.
create table profiles (
id uuid primary key default auth.uid(),
display_name text,
created_at timestamptz not null default now()
);The Users view on the Authentication tab finds a user and can disable, enable or delete them.
Bring your users#
From your server, with the secret key, import users with their bcrypt password hashes, up to 1,000 per call, or every user of a migrated Supabase database. Their passwords keep working.
await server.auth.admin.importUsers([{ email, password_hash }]);
await server.auth.admin.importFromSupabase();Keys#
Rotate the publishable or secret key on the Authentication tab, under Keys. The old key stops working at once, so save the replacement and update your app first.
email_taken, weak_password, invalid_credentials and mfa_required.Next steps#
Updated 27 October 2026