One-method auth adapter
Authentication is one method that turns a request into a user id or null, so any identity provider plugs in without touching a route.
The situation
Acme already signs people in with its own identity provider. Long Tail should trust that sign-in, with no second password and no change to how routes check permissions.
The recipe
import type { LTAuthAdapter, AuthPayload } from '@hotmeshio/long-tail';
class AcmeAdapter implements LTAuthAdapter { async authenticate(req): Promise<AuthPayload | null> { const header = req.headers.authorization; if (!header?.startsWith('Bearer ')) return null; const claims = await verifyAcmeToken(header.slice(7)); return claims ? { userId: claims.sub, email: claims.email } : null; }}
await start({ database: { connectionString: process.env.DATABASE_URL }, auth: { adapter: new AcmeAdapter() }, workers,});null answers 401 before any route runs. With auth.secret instead, the built-in JwtAuthAdapter verifies Long Tail’s own JWTs and recognizes service-account keys by their lt_bot_ prefix. A host that mounts Long Tail behind its own session uses auth.sso.resolve(req) instead, and Long Tail provisions the user on first contact.
The guarantee
Every request passes through the adapter before reaching a handler, and its userId is what all RBAC, claims and audit columns use. Once authenticated, a service-account request is indistinguishable from a person’s: same middleware, same role checks, same identity propagation into workflows. See Auth and SSO.
Related patterns
Agents and MCP
Connect an agent in one line
Add the /mcp URL to any MCP client, sign in once in the browser, and the agent acts as you with your roles as they are now.
Identity
Initiator and principal
A run records who asked and who executes as separate facts, so a service account can do the work while the audit still names the person.
Identity
Member scope profiles
Two scope axes on a membership give five profiles, from full worker to auditor, all enforced inside the query.
