Related docs
Sample project
Neon Auth simplifies user management by bundling auth with your database, so your user data is always available right from Postgres. No custom integration required.
Beta
Neon Auth is in beta and ready to use. We're actively improving it based on feedback from developers like you. Share your experience in our Discord or via the Neon Console.
How it works
When you set up Neon Auth, we create a neon_auth
schema in your database. As users authenticate and manage their profiles in Neon 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 neon_auth.users_sync
table shortly after the Neon Auth processes the updates. Here's an example query to inspect the synchronized data:
SELECT * FROM neon_auth.users_sync;
id | name | created_at | updated_at | deleted_at | raw_json | |
---|---|---|---|---|---|---|
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 neon_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 Neon Auth are automatically reflected in your database.
note
Do not try to change the neon_auth.users_sync
table name. It's needed for the synchronization process to work correctly.
Let's take a look at how Neon Auth simplifies database operations in a typical todos application, specifically when associating todos with users.
Before Neon Auth
Without Neon Auth, you would typically need to:
- Create and manage your own
users
table to store user information in your database. - Implement synchronization logic to keep this
users
table in sync with your authentication provider. This includes handling user creation and, crucially, user updates and deletions. - Create a
todos
table that references yourusers
table using a foreign key.
Here's how you would structure your database and perform insert operations without Neon Auth:
1. Create ausers
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 theusers
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 yourusers
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 }); } }
note
- This code snippet only handles the
user.created
event. To achieve complete synchronization, you would need to write separate webhook handlers foruser.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 atodos
table with a foreign key to theusers
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 theusers
table:INSERT INTO todos (task, user_id) VALUES ('Buy groceries', 'user-id-123');
- Create and manage your own
After Neon Auth
With Neon Auth, Neon automatically creates and manages the
neon_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 Neon Auth:Users table
neon_auth.users_sync
table is automatically created and kept in sync by Neon 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 neon_auth.users_sync table ( automatically created by Neon Auth ) id TEXT PRIMARY KEY, raw_json JSONB, name TEXT, email TEXT, created_at TIMESTAMPTZ, deleted_at TIMESTAMPTZ, updated_at TIMESTAMPTZ
1. Create atodos
table with a foreign key to theneon_auth.users_sync
table:CREATE TABLE todos ( id SERIAL PRIMARY KEY, task TEXT NOT NULL, user_id TEXT NOT NULL REFERENCES neon_auth.users_sync(id) ON DELETE CASCADE, created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP );
2. Insert a todo, referencing theneon_auth.users_sync
table:INSERT INTO todos (task, user_id)
Need help?
Join our Discord Server to ask questions or see what others are doing with Neon. Users on paid plans can open a support ticket from the console. For more details, see Getting Support.