Skip to main content
how-to

Authenticate your dashboard users

Task​

Add your own authentication layer (Clerk, Auth.js, or any provider) to the Mission Control dashboard so multiple people can access it — while understanding that Ethos itself is not multi-user.

Result​

Dashboard visitors log in through your auth provider before accessing Ethos data. Unauthenticated requests never reach the Ethos API.

Prereqs​

Security model​

warning

Ethos is a single-user server. There is no concept of per-user permissions, per-user sessions, or per-user memory inside Ethos. An API key grants full access to every scope it carries — sessions, memory, tool execution, personality switching. Anyone who holds the key has the same access as the Ethos owner.

LayerAuth modelWhat it controls
Your dashboardMulti-user (Clerk, Auth.js, etc.)Who can open the dashboard
Ethos serverSingle-user (one API key = full access)What the dashboard can do

Your auth layer protects the dashboard. It does not protect Ethos from a leaked API key. Treat the API key like a database password — do not embed it in client-side code that untrusted users can inspect.

Steps​

1. Move the API key server-side​

The example Mission Control stores the API key in NEXT_PUBLIC_ETHOS_API_KEY, which is visible in the browser bundle. For a multi-user dashboard, move it behind a server-side proxy:

// src/app/api/ethos/[...path]/route.ts
import { NextRequest, NextResponse } from 'next/server';

const ETHOS_BASE = process.env.ETHOS_BASE_URL!; // no NEXT_PUBLIC_ prefix
const ETHOS_KEY = process.env.ETHOS_API_KEY!; // server-only

export async function POST(req: NextRequest) {
// your auth check here — reject if not authenticated
const body = await req.json();

const res = await fetch(`${ETHOS_BASE}/rpc`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${ETHOS_KEY}`,
},
body: JSON.stringify(body),
});

return NextResponse.json(await res.json());
}

The API key never leaves the server. The browser talks to your Next.js API route, which proxies to Ethos.

2. Add auth middleware​

With Clerk:

// middleware.ts
import { clerkMiddleware } from '@clerk/nextjs/server';

export default clerkMiddleware();

export const config = {
matcher: ['/((?!_next|favicon.ico).*)'],
};

With Auth.js:

// middleware.ts
export { auth as middleware } from '@/auth';

Both approaches gate every route. Unauthenticated visitors are redirected to the login page.

3. Gate the API proxy​

Check authentication inside the proxy route:

// Clerk example
import { auth } from '@clerk/nextjs/server';

export async function POST(req: NextRequest) {
const { userId } = await auth();
if (!userId) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}

// proxy to Ethos
}

4. Adjust the client​

Point EthosClient at your proxy instead of Ethos directly:

const ethos = new EthosClient({
baseUrl: '/api/ethos', // your Next.js API route
// no apiKey — the proxy adds it server-side
});

For SSE, you need a separate proxy path that streams the response body. The proxy sets the Authorization header; the browser receives the event stream without seeing the key.

5. Audit logging (optional)​

Log which dashboard user triggered each Ethos action:

export async function POST(req: NextRequest) {
const { userId } = await auth();
console.log(`[ethos-proxy] user=${userId} action=${req.url}`);
// ...
}

Ethos does not know about your users. Any audit trail that maps dashboard users to Ethos actions must live in your proxy layer.

Verify​

Open the dashboard in an incognito window. The auth provider's login page loads first; the dashboard never renders unauthenticated. After signing in, RPC calls succeed. In the browser Network tab, requests target your /api/ethos/* proxy — no Authorization: Bearer header is visible on the browser side. The Ethos key only travels between your proxy and Ethos.

What this does NOT do​

  • Per-user Ethos sessions — all dashboard users share the same Ethos session pool. One user can see and delete another user's sessions.
  • Per-user memory — MEMORY.md and USER.md are shared. Ethos has one memory scope per personality, not per dashboard user.
  • Permission scoping — the API key grants the same access to every authenticated user. Role-based access (e.g., read-only for some users) must be enforced in your proxy layer.

If your use case requires true multi-user isolation, run a separate Ethos instance per user.