AuthContext is SDK request metadata, not a verified Convex identity or an authorization policy. Tenant propagation varies by operation. Validate the authenticated identity and tenant on your trusted server, authorize every read and mutation there, and keep administrative APIs behind that boundary. Do not expose a privileged Convex deployment directly to untrusted clients or rely on IDs and client-side filters as access controls.
Authentication
Understanding authentication context in Cortex for user tracking, multi-tenancy, and session management.
Overview
Auth context is just data — not a protocol or SDK. Extract it from your auth system (whatever that is) and pass it to Cortex.
Auth0 • Clerk • JWT • NextAuth • Custom
userId • tenantId • sessionId • metadata
Auto-injects auth to ALL operations
Why Authentication Matters
User Tracking
Link all data to users for personalization and context
Multi-Tenancy
Complete data separation for SaaS platforms
GDPR Compliance
Enable cascade deletion across all layers
Session Management
Track user activity across devices
Quick Start
Extract Auth Information
From your auth system (JWT, session, OAuth token):
import jwt from "jsonwebtoken";
function extractAuth(token: string) {
const decoded = jwt.verify(token, process.env.JWT_SECRET!) as {
sub: string;
tenant_id?: string;
session_id?: string;
};
return {
userId: decoded.sub,
tenantId: decoded.tenant_id,
sessionId: decoded.session_id,
};
}
Create Auth Context
import { createAuthContext } from "@cortexmemory/sdk";
const auth = createAuthContext({
userId: extracted.userId,
tenantId: extracted.tenantId,
sessionId: extracted.sessionId,
});
Initialize Cortex
import { Cortex } from "@cortexmemory/sdk";
const cortex = new Cortex({
convexUrl: process.env.CONVEX_URL!,
auth,
});
Use Cortex
Supported operations use auth context as default request metadata:
await cortex.memory.remember({
memorySpaceId: "user-space",
userMessage: "Hello",
agentResponse: "Hi!",
userName: "User",
conversationId: "conversation-example",
// userId, tenantId auto-injected
});
Auth Context Fields
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
userId | string | Yes | — | Identifies the authenticated user. Default user metadata for supported operations. |
tenantId | string | No | — | Multi-tenant SaaS isolation. Tenant metadata for supported operations; enforce authorization on the server. |
sessionId | string | No | — | Track user sessions across devices. |
claims | object | No | — | Raw data from auth provider (email, iss, aud, etc.) |
metadata | object | No | — | Your application data (role, plan, features, etc.) |
Example with All Fields
const auth = createAuthContext({
userId: "user-123", // Required
tenantId: "customer-acme", // Multi-tenant isolation
sessionId: "session-xyz", // Session tracking
claims: {
email: "user@example.com",
iss: "https://auth.myapp.com",
},
metadata: {
role: "admin",
plan: "enterprise",
},
});
Common Patterns
// Middleware extracts auth
app.use((req, res, next) => {
const token = req.headers.authorization?.replace("Bearer ", "");
if (!token) return res.status(401).send("Unauthorized");
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET!);
req.auth = createAuthContext({
userId: decoded.sub,
tenantId: decoded.tenant_id,
sessionId: decoded.session_id,
});
next();
} catch (err) {
res.status(401).send("Invalid token");
}
});
// Route uses auth
app.post("/chat", (req, res) => {
const cortex = new Cortex({ convexUrl, auth: req.auth });
// Use cortex...
});
// Single-user CLI tool — no tenants needed
const auth = createAuthContext({
userId: "local-user",
metadata: { hostname: os.hostname() },
});
const cortex = new Cortex({ convexUrl, auth });
// Service account for automated tasks
const serviceAuth = createAuthContext({
userId: "service-session-cleanup",
metadata: {
type: "service_account",
purpose: "cleanup",
},
});
const cortex = new Cortex({ convexUrl, auth: serviceAuth });
Security Best Practices
// GOOD: From signed JWT
const decoded = jwt.verify(token, secret);
const auth = createAuthContext({
userId: decoded.sub,
tenantId: decoded.tenant_id, // From secure source
});
// BAD: From client input — user could change this!
const auth = createAuthContext({
userId: decoded.sub,
tenantId: req.body.tenantId, // NEVER do this
});
async function validateAuth(auth: AuthContext) {
const user = await cortex.users.get(auth.userId);
if (!user) throw new Error("User not found");
return true;
}
// Expire old sessions periodically
await cortex.sessions.expireIdle({
idleTimeout: 30 * 60 * 1000, // 30 minutes
});