@dcimorra/authhub-sdk
v1.4.0
Published
Official TypeScript SDK for Auth Hub — self-hosted authentication, OAuth social login, webhooks, realtime subscriptions, database, schema management, and storage as a service
Maintainers
Readme
@dcimorra/authhub-sdk
Official TypeScript SDK for Auth Hub — self-hosted authentication, database, schema management, storage, OAuth, realtime subscriptions, and cookie-based sessions as a service.
Install
npm install @dcimorra/authhub-sdkOr copy the sdk/ directory into your project and import from it directly.
Quick Start
import { AuthHubClient } from "@dcimorra/authhub-sdk";
const hub = new AuthHubClient({
baseUrl: "https://auth.example.com",
projectId: "your-project-uuid",
apiKey: "sk_your_api_key",
});Authentication
// Register
await hub.auth.register("[email protected]", "securePassword123");
// Login — tokens are stored automatically
const { user } = await hub.auth.login("[email protected]", "securePassword123");
// Get current user (auto-refreshes token if expired)
const me = await hub.auth.getUser();
// Change password
await hub.auth.changePassword("oldPassword", "newPassword");
// Password recovery flow
await hub.auth.recover("[email protected]");
// User receives email with token...
await hub.auth.resetPassword(tokenFromEmail, "newPassword");
// Logout — clears tokens locally and revokes on server
await hub.auth.logout();
// Check auth state
const isLoggedIn = await hub.auth.isAuthenticated();Token Management
Tokens are automatically stored and refreshed. You can customize the storage:
// Browser (default): localStorage
const hub = new AuthHubClient({ ..., tokenStore: "localStorage" });
// Node.js (default): in-memory
const hub = new AuthHubClient({ ..., tokenStore: "memory" });
// Custom store (e.g. React Native AsyncStorage)
const hub = new AuthHubClient({
...,
tokenStore: {
get: (key) => AsyncStorage.getItem(key),
set: (key, value) => AsyncStorage.setItem(key, value),
remove: (key) => AsyncStorage.removeItem(key),
},
});
// Handle session expiry (refresh token expired/revoked)
const hub = new AuthHubClient({
...,
onSessionExpired: () => {
window.location.href = "/login";
},
});Session (Cookie-Based SSR Auth)
For server-side apps like Next.js where you need cookie-based sessions instead of token-based auth:
// Login — returns the user and Set-Cookie headers to forward to the browser
const { user, setCookieHeaders } = await hub.session.login(email, password);
const response = NextResponse.json({ success: true });
for (const h of setCookieHeaders) response.headers.append("Set-Cookie", h);
// Validate a session by forwarding browser cookies
const cookieHeader = request.headers.get("cookie") || "";
const user = await hub.session.validate(cookieHeader); // User | null
// Logout — returns Set-Cookie headers that clear the session cookies
const setCookieHeaders = await hub.session.logout(cookieHeader);
const response = NextResponse.json({ success: true });
for (const h of setCookieHeaders) response.headers.append("Set-Cookie", h);
// Change password via session cookies
await hub.session.changePassword(cookieHeader, "oldPassword", "newPassword");Database
Full CRUD with advanced query operators.
// Insert
const { rows } = await hub.db.create({
table: "products",
data: { name: "Widget", price: 29.99, active: true },
});
// Query with operators
const { rows, count } = await hub.db.read({
table: "products",
select: ["id", "name", "price"],
where: {
price: { $gte: 10, $lte: 100 },
status: { $in: ["active", "sale"] },
deleted_at: { $is: null },
},
orderBy: [
{ column: "price", order: "ASC" },
{ column: "name", order: "DESC" },
],
limit: 50,
offset: 0,
});
// Update
await hub.db.update({
table: "products",
data: { price: 24.99 },
where: { id: 1 },
});
// Delete
await hub.db.delete({
table: "products",
where: { active: false },
});
// Convenience methods
const product = await hub.db.findById("products", 1);
const user = await hub.db.findOne("users", { email: "[email protected]" });
const total = await hub.db.count("products", { active: true });Query Operators
| Operator | SQL | Example |
|----------|-----|---------|
| $eq | = | { status: { $eq: "active" } } |
| $neq | != | { role: { $neq: "admin" } } |
| $gt | > | { price: { $gt: 10 } } |
| $gte | >= | { age: { $gte: 18 } } |
| $lt | < | { stock: { $lt: 5 } } |
| $lte | <= | { priority: { $lte: 3 } } |
| $in | IN (...) | { status: { $in: ["a", "b"] } } |
| $nin | NOT IN (...) | { id: { $nin: [1, 2, 3] } } |
| $like | LIKE | { name: { $like: "%widget%" } } |
| $ilike | ILIKE | { name: { $ilike: "%Widget%" } } |
| $is | IS | { deleted_at: { $is: null } } |
| $not | IS NOT | { email: { $not: null } } |
Schema Management (DDL)
Create and modify tables, columns, and constraints remotely via the API. Each project gets its own isolated PostgreSQL database.
// List all tables
const { tables } = await hub.schema.listTables();
// => ["articles", "comments"]
// Create a table (comes with `id SERIAL PRIMARY KEY` and `created_at TIMESTAMP`)
await hub.schema.createTable("articles");
// Get table details (columns + constraints)
const info = await hub.schema.getTable("articles");
console.log(info.columns); // SchemaColumn[]
console.log(info.constraints); // SchemaConstraint[]
// Add columns
await hub.schema.addColumn("articles", {
column: "title",
type: "TEXT",
nullable: false,
});
await hub.schema.addColumn("articles", {
column: "status",
type: "TEXT",
nullable: false,
default: "draft",
});
await hub.schema.addColumn("articles", {
column: "updated_at",
type: "TIMESTAMP",
default: "CURRENT_TIMESTAMP",
});
// Rename a column
await hub.schema.renameColumn("articles", {
column: "title",
newName: "headline",
});
// Drop a column (cannot drop system columns: id, created_at, updated_at)
await hub.schema.dropColumn("articles", "old_field");
// Add a unique constraint
await hub.schema.addConstraint("articles", {
constraintType: "unique",
columns: ["slug"],
name: "uq_articles_slug", // optional, auto-generated if omitted
});
// Add a foreign key
await hub.schema.addConstraint("comments", {
constraintType: "foreign_key",
columns: ["article_id"],
referencedTable: "articles",
referencedColumns: ["id"],
onDelete: "CASCADE",
onUpdate: "NO ACTION",
});
// Drop a constraint
await hub.schema.dropConstraint("articles", "uq_articles_slug");
// Drop a table (CASCADE)
await hub.schema.dropTable("old_table");Supported Column Types
TEXT, INTEGER, BIGINT, SMALLINT, REAL, DOUBLE PRECISION, BOOLEAN, DATE, TIME, TIMESTAMP, NUMERIC, DECIMAL, VARCHAR, CHAR
Supported Foreign Key Actions
NO ACTION, RESTRICT, CASCADE, SET NULL, SET DEFAULT
Storage
File upload, download, and bucket management.
// Create a bucket
await hub.storage.createBucket({
name: "avatars",
isPublic: true,
maxFileSize: 5 * 1024 * 1024, // 5MB
});
// Upload a file (browser)
const fileInput = document.querySelector<HTMLInputElement>("#file");
await hub.storage.upload({
bucket: "avatars",
key: "users/user1.jpg",
file: fileInput.files[0],
});
// Upload from Node.js
import { readFileSync } from "fs";
await hub.storage.upload({
bucket: "avatars",
key: "users/user1.jpg",
file: readFileSync("photo.jpg"),
contentType: "image/jpeg",
});
// Download
const response = await hub.storage.download("avatars", "users/user1.jpg");
const blob = await response.blob(); // browser
// or
const buffer = await hub.storage.downloadBuffer("avatars", "users/user1.jpg");
// Public URL (for <img src=...> etc.)
const url = hub.storage.getPublicUrl("avatars", "users/user1.jpg");
// List files
const { objects, count } = await hub.storage.list({
bucket: "avatars",
prefix: "users/",
limit: 50,
});
// Delete
await hub.storage.deleteObject("avatars", "users/user1.jpg");
// Bucket management
const buckets = await hub.storage.listBuckets();
await hub.storage.deleteBucket("old-bucket");OAuth
Social login with Google and GitHub.
// Get the OAuth URL and redirect the user
const url = hub.oauth.getAuthUrl("google", "/dashboard");
window.location.href = url;
// Or use the convenience method (browser only)
hub.oauth.signInWithProvider("github", "/dashboard");
// After the redirect, parse tokens from the URL hash
const result = await hub.oauth.handleCallback();
if (result) {
console.log(result.provider); // "google" | "github"
console.log(result.access_token); // tokens are also stored automatically
}Realtime
Subscribe to database mutations via WebSocket.
// Create a realtime client
const realtime = hub.realtime("wss://auth.example.com");
// Connect and authenticate
const accessToken = await hub.auth.getAccessToken();
await realtime.connect(accessToken);
// Subscribe to table changes
realtime.on("table:users", (event, data) => {
console.log(event); // "INSERT" | "UPDATE" | "DELETE"
console.log(data); // { table, operation, id, timestamp }
});
// Subscribe with confirmation
await realtime.subscribe("table:orders", (event, data) => {
console.log("Order changed:", event, data);
});
// Unsubscribe
realtime.unsubscribe("table:users");
// Remove a specific handler
realtime.off("table:orders", myHandler);
// Check connection state
console.log(realtime.isConnected());
// Close when done
realtime.close();Error Handling
All methods throw AuthHubError on failure:
import { AuthHubError } from "@dcimorra/authhub-sdk";
try {
await hub.auth.login("[email protected]", "wrong-password");
} catch (err) {
if (err instanceof AuthHubError) {
console.log(err.message); // "Invalid credentials"
console.log(err.status); // 401
console.log(err.code); // optional error code
}
}Build from Source
cd sdk
npm install
npm run buildThis produces dist/ with CJS, ESM, and type declarations.
