A flexible authentication system with user registration, login/logout, password reset, and session management.
- User Management: Registration, login, profile management
- Authentication: JWT-based authentication with access and refresh tokens
- Password Management: Secure password hashing, validation, reset
- Email Verification: Email verification for new accounts
- Adapters: Pluggable storage adapters (memory, Supabase, MySQL, PostgreSQL, MongoDB, PocketBase, etc.)
- Middleware: Express/Connect/Hono middleware for protected routes
- Validation: Input validation for emails, passwords, etc.
- Customization: Configurable password requirements, token expiry, etc.
npm install @profullstack/auth-systemimport { createAuthSystem } from '@profullstack/auth-system';
// Create an auth system with default options
const authSystem = createAuthSystem({
tokenOptions: {
secret: 'your-secret-key-here',
accessTokenExpiry: 3600, // 1 hour
refreshTokenExpiry: 604800 // 7 days
}
});
// Register a new user
const registrationResult = await authSystem.register({
email: 'user@example.com',
password: 'Password123',
profile: {
firstName: 'John',
lastName: 'Doe'
}
});
// Login
const loginResult = await authSystem.login({
email: 'user@example.com',
password: 'Password123'
});
// Use the tokens for authentication
const { accessToken, refreshToken } = loginResult.tokens;import { createAuthSystem, MemoryAdapter } from '@profullstack/auth-system';
const authSystem = createAuthSystem({
// Storage adapter (optional, defaults to in-memory)
adapter: new MemoryAdapter(),
// Token configuration (optional)
tokenOptions: {
accessTokenExpiry: 3600, // 1 hour
refreshTokenExpiry: 604800, // 7 days
secret: 'your-secret-key-here'
},
// Password configuration (optional)
passwordOptions: {
minLength: 8,
requireUppercase: true,
requireLowercase: true,
requireNumbers: true,
requireSpecialChars: false
},
// Email configuration (optional)
emailOptions: {
sendEmail: async (emailData) => {
// Your email sending implementation
},
fromEmail: 'noreply@example.com',
resetPasswordTemplate: {
subject: 'Reset Your Password',
text: 'Click the link to reset your password: {resetLink}',
html: '<p>Click the link to reset your password: <a href="{resetLink}">{resetLink}</a></p>'
},
verificationTemplate: {
subject: 'Verify Your Email',
text: 'Click the link to verify your email: {verificationLink}',
html: '<p>Click the link to verify your email: <a href="{verificationLink}">{verificationLink}</a></p>'
}
}
});const registrationResult = await authSystem.register({
email: 'user@example.com',
password: 'Password123',
profile: {
firstName: 'John',
lastName: 'Doe'
},
autoVerify: false // Set to true to skip email verification
});const loginResult = await authSystem.login({
email: 'user@example.com',
password: 'Password123'
});
// The login result contains user data and tokens
const { user, tokens } = loginResult;const refreshResult = await authSystem.refreshToken(refreshToken);
// The refresh result contains new tokens
const { accessToken, refreshToken } = refreshResult.tokens;// Request password reset
const resetResult = await authSystem.resetPassword('user@example.com');
// Confirm password reset (in a real app, the token would come from the email link)
const confirmResult = await authSystem.resetPasswordConfirm({
token: 'reset-token-from-email',
password: 'NewPassword123'
});// Verify email (in a real app, the token would come from the email link)
const verificationResult = await authSystem.verifyEmail('verification-token-from-email');// Get user profile
const profileResult = await authSystem.getProfile(userId);
// Update user profile
const updateResult = await authSystem.updateProfile({
userId,
profile: {
firstName: 'John',
lastName: 'Doe',
phoneNumber: '555-123-4567'
}
});
// Change password
const changePasswordResult = await authSystem.changePassword({
userId,
currentPassword: 'Password123',
newPassword: 'NewPassword123'
});// Validate an access token
const user = await authSystem.validateToken(accessToken);
if (user) {
// Token is valid, user contains user data
console.log(`Valid token for user: ${user.email}`);
} else {
// Token is invalid or expired
console.log('Invalid token');
}// Logout (invalidates the refresh token)
const logoutResult = await authSystem.logout(refreshToken);import express from 'express';
import { createAuthSystem } from '@profullstack/auth-system';
const app = express();
const authSystem = createAuthSystem();
// Protect routes with authentication middleware
app.use('/api/protected', authSystem.middleware());
app.get('/api/protected/profile', (req, res) => {
// req.user contains the authenticated user data
res.json({ user: req.user });
});
app.listen(3000);Stores user data in memory. Suitable for development or testing.
import { createAuthSystem, MemoryAdapter } from '@profullstack/auth-system';
const authSystem = createAuthSystem({
adapter: new MemoryAdapter()
});Uses JSON Web Tokens (JWT) for authentication. Requires a database adapter for user storage.
import { createAuthSystem, MemoryAdapter, JwtAdapter } from '@profullstack/auth-system';
const dbAdapter = new MemoryAdapter();
const jwtAdapter = new JwtAdapter({
dbAdapter,
secret: 'your-secret-key-here'
});
const authSystem = createAuthSystem({
adapter: jwtAdapter
});Uses Supabase for user storage and authentication. Requires the @supabase/supabase-js package.
import { createAuthSystem, SupabaseAdapter } from '@profullstack/auth-system';
const supabaseAdapter = new SupabaseAdapter({
supabaseUrl: 'https://your-project-id.supabase.co',
supabaseKey: 'your-supabase-api-key',
tableName: 'users', // Optional: defaults to 'users'
tokensTableName: 'invalidated_tokens' // Optional: defaults to 'invalidated_tokens'
});
const authSystem = createAuthSystem({
adapter: supabaseAdapter,
tokenOptions: {
secret: 'your-jwt-secret-key'
}
});Note: Before using the Supabase adapter, you need to set up the required tables in your Supabase database. You can use the supabase-schema.sql file to create the necessary tables and indexes.
Uses MySQL for user storage and authentication. Requires the mysql2 package.
import { createAuthSystem, MySQLAdapter } from '@profullstack/auth-system';
const mysqlAdapter = new MySQLAdapter({
host: 'localhost',
port: 3306,
database: 'auth_system',
user: 'root',
password: 'password',
usersTable: 'users', // Optional: defaults to 'users'
tokensTable: 'invalidated_tokens' // Optional: defaults to 'invalidated_tokens'
});
const authSystem = createAuthSystem({
adapter: mysqlAdapter,
tokenOptions: {
secret: 'your-jwt-secret-key'
}
});Note: This is a stub implementation. You'll need to complete the implementation before using it in production.
Uses PostgreSQL for user storage and authentication. Requires the pg package.
import { createAuthSystem, PostgresAdapter } from '@profullstack/auth-system';
const postgresAdapter = new PostgresAdapter({
host: 'localhost',
port: 5432,
database: 'auth_system',
user: 'postgres',
password: 'password',
usersTable: 'users', // Optional: defaults to 'users'
tokensTable: 'invalidated_tokens' // Optional: defaults to 'invalidated_tokens'
});
const authSystem = createAuthSystem({
adapter: postgresAdapter,
tokenOptions: {
secret: 'your-jwt-secret-key'
}
});Note: This is a stub implementation. You'll need to complete the implementation before using it in production.
Uses MongoDB for user storage and authentication. Requires the mongodb package.
import { createAuthSystem, MongoDBAdapter } from '@profullstack/auth-system';
const mongodbAdapter = new MongoDBAdapter({
uri: 'mongodb://localhost:27017',
dbName: 'auth_system',
usersCollection: 'users', // Optional: defaults to 'users'
tokensCollection: 'invalidated_tokens' // Optional: defaults to 'invalidated_tokens'
});
const authSystem = createAuthSystem({
adapter: mongodbAdapter,
tokenOptions: {
secret: 'your-jwt-secret-key'
}
});Note: This is a stub implementation. You'll need to complete the implementation before using it in production.
Uses PocketBase for user storage and authentication. Requires the pocketbase package.
import { createAuthSystem, PocketBaseAdapter } from '@profullstack/auth-system';
const pocketbaseAdapter = new PocketBaseAdapter({
url: 'http://127.0.0.1:8090',
usersCollection: 'auth_users', // Optional: defaults to 'auth_users'
tokensCollection: 'auth_invalidated_tokens', // Optional: defaults to 'auth_invalidated_tokens'
adminEmail: 'admin@example.com', // Optional: for admin authentication
adminPassword: 'password' // Optional: for admin authentication
});
const authSystem = createAuthSystem({
adapter: pocketbaseAdapter,
tokenOptions: {
secret: 'your-jwt-secret-key'
}
});You can create custom adapters by implementing the adapter interface:
class CustomAdapter {
async createUser(userData) { /* ... */ }
async getUserById(userId) { /* ... */ }
async getUserByEmail(email) { /* ... */ }
async updateUser(userId, updates) { /* ... */ }
async deleteUser(userId) { /* ... */ }
async invalidateToken(token) { /* ... */ }
async isTokenInvalidated(token) { /* ... */ }
}Note: Before using the PocketBase adapter, you need to set up the required collections in your PocketBase database. You can use the pocketbase-schema.json file to create the necessary collections and indexes.
Every Profullstack app signs its CLI, TUI, stdio MCP server and desktop shell in the same way, so the pieces live here instead of being rebuilt per app.
Server (@profullstack/auth-system/oauth2): authorization code + PKCE S256
only, RFC 8252 loopback redirects, single-use 5-minute codes, 1-hour access
tokens, refresh tokens that rotate on every use, and reuse detection that revokes
the whole sign-in. Only hashes are stored.
import { createOAuthServer } from '@profullstack/auth-system/oauth2';
import { OAUTH2_SCHEMA, postgresStore } from '@profullstack/auth-system/oauth2/postgres';
await sql.unsafe(OAUTH2_SCHEMA); // once, idempotent
const oauth = createOAuthServer({
store: postgresStore(sql),
issuer: 'https://example.com',
tokenPrefix: 'ex',
clients: { 'example-cli': { name: 'example CLI', redirectUris: ['http://127.0.0.1/callback', 'https://example.com/oauth/cli'] } },
});
// GET /oauth/authorize -> oauth.validateAuthorize(query), show consent, then redirect to oauth.approve({...params, userId})
// POST /oauth/token -> oauth.token(formBody)
// POST /oauth/revoke -> oauth.revoke(formBody.token)
// GET /.well-known/oauth-authorization-server -> oauth.metadata()
// API auth: await oauth.verifyAccessToken(req.headers.authorization)Client (@profullstack/auth-system/cli): opens the browser, waits on a
loopback port, checks state, exchanges the code with its PKCE verifier and keeps
the tokens at ~/.config/<app>/auth.json (0600). Over SSH it prints the URL and
asks for the code the server's /oauth/cli page shows.
import { createTokenStore, getAccessToken, login, logout } from '@profullstack/auth-system/cli';
const store = createTokenStore('example');
await login({ issuer: 'https://example.com', clientId: 'example-cli', store });
const bearer = await getAccessToken({ store }); // refreshes + stores the rotated pair
await logout({ store }); // revokes server-side, forgets locallySee the examples directory for complete usage examples:
- Basic Usage: Simple example of using the auth system
- Supabase Usage: Example of using the auth system with Supabase
- Supabase Schema: SQL schema for setting up Supabase tables
- PocketBase Usage: Example of using the auth system with PocketBase
- PocketBase Schema: JSON schema for setting up PocketBase collections
- Browser Integration: Complete example of integrating the auth system into a browser-based web application
The browser integration example provides a complete authentication system for web applications, including:
- User registration with payment integration (Stripe, crypto)
- Login/logout functionality
- Password reset and change
- Profile management
- API key management
- Authentication status utilities
It includes a browser-friendly wrapper around the auth-system module with localStorage support and event handling. See the Browser Integration README for more details.
MIT