LogoZonai

Auth Tables

How to define tables with built-in authentication (password, OTP, magic link).

An auth table is a regular table with built-in authentication endpoints. Use authTable() instead of table(), and extend AuthTable<T> instead of Table<T>. Mix in one or more auth methods to enable the corresponding sign-in flows.

Auth tables still get normal CRUD and live streams (/db/stream*). After sign-in, use client.db.listen for live data — Streaming.

Auth Mixins#

MixinSign-in MethodDocs
PasswordAuth Email + password Password Auth
OtpAuth One-time passcode via email OTP Auth
MagicLinkAuth Single-use emailed link Magic Link Auth

A table can use multiple mixins simultaneously:

final class UserTable extends AuthTable<User>
    with PasswordAuth, OtpAuth, MagicLinkAuth {
  // ...
}

Built-in Fields#

All auth tables automatically get these columns — you declare them in the class but do not need to define the underlying SQL:

ColumnMethodTypeNotes
email $.email(...) TEXT UNIQUE NOT NULL The user's identity
isVerified $.isVerified(...) BOOL NOT NULL false after sign-up

PasswordAuth adds:

ColumnMethodTypeNotes
password $.password(...) TEXT Argon2id hash — never returned in responses

OtpAuth and MagicLinkAuth add no persistent columns — their tokens are transient.

Auth Endpoints#

Auth endpoints use the table field in the request body to identify which auth table to target. The endpoints themselves are not table-namespaced:

EndpointDescription
POST /auth/sign-upCreate an account (PasswordAuth)
POST /auth/sign-inSign in with email + password (PasswordAuth)
POST /authRequest OTP or magic link
POST /auth/confirmVerify OTP, magic link, email, or password reset
POST /auth/refreshRefresh the access token
DELETE /authRevoke current token (logout)
DELETE /auth/allRevoke all tokens (logout everywhere)
POST /auth/reset-passwordRequest password reset email
POST /auth/verify-emailResend email verification

See the Authentication section for request/response shapes.

Adding Custom Fields#

Add any extra columns alongside the built-in auth fields. They are readable and writable via the standard /db/<table> API:

final class UserTable extends AuthTable<User> with PasswordAuth {
  UserTable(super.$)
    : id = $.id('id', ...),
      email = $.email('email', ...),
      isVerified = $.isVerified('is_verified', ...),
      name = $.text('name', (s) => s.name),       // custom field
      plan = $.text('plan', (s) => s.plan),        // custom field
      createdAt = $.createdAt('created_at', ...),
      updatedAt = $.updatedAt('updated_at', ...),
      passwordHash = $.password('password', ...);
  // ...
}

Custom fields can be embedded in JWT claims via Auth Operations.

Complete Example#

import 'package:zonai_schema/zonai_schema.dart';

final class User {
  const User({
    required this.id, required this.email, required this.isVerified,
    required this.name, required this.createdAt, required this.updatedAt,
    required this.passwordHash,
  });
  final UsersId id;
  final String email;
  final bool isVerified;
  final String name;
  final DateTime createdAt;
  final DateTime updatedAt;
  final String passwordHash;
}

class UsersId extends Id {
  const UsersId(super.value);
  factory UsersId.generate() => UsersId(Id.generate('us'));
}

final class UserTable extends AuthTable<User> with PasswordAuth, OtpAuth {
  UserTable(super.$)
    : id = $.id('id', (s) => s.id, fromString: UsersId.new, generate: UsersId.generate),
      email = $.email('email', (s) => s.email),
      isVerified = $.isVerified('is_verified', (s) => s.isVerified),
      name = $.text('name', (s) => s.name),
      createdAt = $.createdAt('created_at', (s) => s.createdAt),
      updatedAt = $.updatedAt('updated_at', (s) => s.updatedAt),
      passwordHash = $.password('password', (s) => s.passwordHash);

  @override
  User fromRow(RowReader read) => User(
    id: read(id), email: read(email), isVerified: read(isVerified),
    name: read(name), createdAt: read(createdAt), updatedAt: read(updatedAt),
    passwordHash: read(passwordHash),
  );

  final IdColumn<UsersId> id;
  final EmailColumn email;
  final IsVerifiedColumn isVerified;
  final TextColumn name;
  final CreatedAtColumn createdAt;
  final UpdatedAtColumn updatedAt;
  final PasswordColumn passwordHash;
}

final users = authTable('users', UserTable.new);