How It Works
Get started Tutorial SerenDB Auth Demo App
SerenDB Auth simplifies user management by bundling auth with your database, so your user data is always available right from Postgres. No custom integration required.
How it works
When you set up SerenDB Auth, we create a seren_auth schema in your database. As users authenticate and manage their profiles in SerenDB Auth, you'll see them appear in your list of users on the Auth page.

User data is immediately available in your database
User data is available in the seren_auth.users_sync table shortly after the SerenDB Auth processes the updates. Here's an example query to inspect the synchronized data:
SELECT * FROM seren_auth.users_sync;d37b6a30...
Jordan Rivera
jordan@company.co
2025-05-09 16:15:00
null
null
{\"id\": \"d37b6a30...\", ...}
51e491df...
Sam Patel
sam@startup.dev
2025-02-27 18:36:00
2025-02-27 18:36:00
null
{\"id\": \"51e491df...\", ...}
The following columns are included in the seren_auth.users_sync table:
raw_json: Complete user profile as JSONid: The unique ID of the username: The user's display nameemail: The user's primary emailcreated_at: When the user signed updeleted_at: When the user was deleted, if applicable (nullable)updated_at: When the user was last updated, if applicable (nullable)
Updates to user profiles in SerenDB Auth are automatically reflected in your database.
Do not try to change the `seren_auth.users_sync` table name. It's needed for the synchronization process to work correctly.
Let's take a look at how SerenDB Auth simplifies database operations in a typical todos application, specifically when associating todos with users.
Before SerenDB Auth
Without SerenDB Auth, you would typically need to:
Create and manage your own
userstable to store user information in your database.Implement synchronization logic to keep this
userstable in sync with your authentication provider. This includes handling user creation and, crucially, user updates and deletions.Create a
todostable that references youruserstable using a foreign key.
Here's how you would structure your database and perform insert operations without SerenDB Auth:
1. Create a users table:
users table:CREATE TABLE users (
id TEXT PRIMARY KEY, -- User ID from your auth provider (TEXT type)
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(255),
-- ... other user fields
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ
);2. Insert a user into the users table:
users table:To insert this user into your database when a new user is created in your auth provider, you might set up a webhook endpoint. Here's an example of a simplified webhook handler that would receive a user.created event from your auth provider and insert the user into your users table:
// Webhook handler to insert a user into the 'users' table for a 'user.created' event
import { db } from '@/db';
export async function POST(request: Request) {
await checkIfRequestIsFromAuthProvider(request); // Validate request authenticity using headers, etc.
const payload = await request.json(); // Auth Provider webhook payload
// Extract user data from the webhook payload
const userId = payload.user_id;
const email = payload.email_address;
const name = payload.name;
try {
await db.query(
`INSERT INTO users (id, email, name)
VALUES ($1, $2, $3)`,
[userId, email, name]
);
return new Response('User added successfully', { status: 200 });
} catch (error) {
console.error('Database error inserting user:', error);
// Retry logic, error handling, etc. as needed
// Send notification to on-call team, etc to check why the insert operation failed
return new Response('Error inserting user into database', { status: 500 });
}
}- This code snippet only handles the `user.created` event. To achieve complete synchronization, you would need to write separate webhook handlers for `user.updated`, `user.deleted`, and potentially other event types. Each handler adds complexity and requires careful error handling, security considerations, and ongoing maintenance. - The provided webhook example is a simplified illustration, and a production-ready solution would necessitate more robust error handling, security measures, and potentially queueing mechanisms to ensure reliable synchronization.
3. Create a todos table with a foreign key to the users table:
todos table with a foreign key to the users table:CREATE TABLE todos (
id SERIAL PRIMARY KEY,
task TEXT NOT NULL,
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);4. Insert a todo, referencing the users table:
users table:INSERT INTO todos (task, user_id)
VALUES ('Buy groceries', 'user-id-123');After SerenDB Auth
With SerenDB Auth, SerenDB automatically creates and manages the seren_auth.users_sync table. User profiles are stored automatically in your database, so you can directly rely on this table for up-to-date user data, simplifying your database operations.
Here's how you would structure your todos table and perform insert operations with SerenDB Auth:
Users table
seren_auth.users_sync table is automatically created and kept in sync by SerenDB Auth (no action needed from you) and is available for direct use in your schema and queries. Here is the table structure as discussed above:
-- schema of seren_auth.users_sync table ( automatically created by SerenDB Auth )
id TEXT PRIMARY KEY,
raw_json JSONB,
name TEXT,
email TEXT,
created_at TIMESTAMPTZ,
deleted_at TIMESTAMPTZ,
updated_at TIMESTAMPTZ1. Create a todos table with a foreign key to the seren_auth.users_sync table:
CREATE TABLE todos (
id SERIAL PRIMARY KEY,
task TEXT NOT NULL,
user_id TEXT NOT NULL REFERENCES seren_auth.users_sync(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);2. Insert a todo, referencing the seren_auth.users_sync table:
INSERT INTO todos (task, user_id)Last updated