ObjectStackObjectStack

IAuthService Contract

Reference for the Auth Service contract — authentication, session verification, user resolution, and logout

IAuthService Contract

The Auth Service handles authentication — verifying user identity through credentials, tokens, or external providers. It does not handle authorization (permissions); that is governed separately by the security layer (PermissionSets, sharing rules) in plugin-security.

Source: packages/spec/src/contracts/auth-service.ts
Service token: 'auth' (the CoreServiceName value; resolve with ctx.getService('auth'))


Interface Definition

export interface IAuthService {
  /** Handle an incoming HTTP authentication request (login, callback, etc.). */
  handleRequest(request: Request): Promise<Response>;

  /** Verify a bearer token or session identifier and return the result. */
  verify(token: string): Promise<AuthResult>;

  /** Invalidate a session (logout). Optional. */
  logout?(sessionId: string): Promise<void>;

  /** Resolve the current user from a request. Optional. */
  getCurrentUser?(request: Request): Promise<AuthUser | undefined>;

  /** The session API, when the provider mounts it directly (legacy shape). Optional. */
  api?: AuthSessionApi;

  /** Resolve the session API, creating the auth instance on first use. Optional. */
  getApi?(): Promise<AuthSessionApi | undefined>;

  /** Whether this deployment's auth gate is live. Optional. */
  isAuthGateActive?(): boolean;

  /** Verify an OAuth 2.1 access token from the embedded AS (MCP surface). Optional. */
  verifyMcpAccessToken?(token: string): Promise<{ userId: string; scopes: string[]; clientId?: string } | undefined>;

  /** The MCP resource identifier (RFC 8707 `resource` / token `aud`). Optional. */
  getMcpResourceUrl?(): string;

  /** RFC 9728 protected-resource metadata URL, or `null` when OAuth is off. Optional. */
  getMcpResourceMetadataUrl?(): string | null;
}

The two required members are the core: it follows the Dependency Inversion Principle so that plugins depend on the contract rather than a concrete provider. Concrete implementations (better-auth, custom, LDAP, etc.) supply the actual logic, and handleRequest works directly with the standard Request/Response types.

Everything after verify is optional, and each optional member describes a capability a provider may or may not have — a caller must probe before use. Two pairs are worth reading together:

  • api and getApi() are the same session handle by two routes. api is the legacy direct mount; getApi() is the lazy accessor, and it is the one to prefer — the shipped plugin-auth registers an AuthManager, which has no api member at all, so a caller that reads only api gets undefined on every current deployment. Read api ?? await getApi?.().
  • getMcpResourceUrl() and getMcpResourceMetadataUrl() both describe the MCP OAuth surface; the second returns null (rather than being absent) when the OAuth track is off for the deployment.

Core Authentication

handleRequest

The HTTP entry point for authentication. It receives a standard Request (login, OAuth callback, etc.) and returns a standard Response. The concrete implementation owns route handling, credential parsing, and cookie/token issuance.

// Wire the auth service into an HTTP handler
const response = await authService.handleRequest(request);
return response;

verify

Validates a bearer token or session identifier and returns an AuthResult. On success the result carries user and session; on failure success is false and error holds a message.

const result = await authService.verify(accessToken);
if (!result.success) {
  throw new Error(result.error ?? 'Invalid or expired token');
}
console.log(result.user?.email); // "jane@example.com"

logout

Invalidates a session by its identifier. This method is optional on the contract.

await authService.logout?.(session.id);

AuthUser Interface

The AuthUser object represents an authenticated user throughout the system.

export interface AuthUser {
  /** User identifier */
  id: string;
  /** Email address */
  email: string;
  /** Display name */
  name: string;
  /** Assigned position identifiers */
  positions?: string[];
  /** Current tenant identifier (multi-tenant) */
  tenantId?: string;
}
PropertyTypeDescription
idstringUnique user identifier
emailstringUser's email address
namestringDisplay name
positionsstring[]?Assigned position identifiers
tenantIdstring?Current tenant identifier (multi-tenant)

User Resolution

getCurrentUser

Resolves the authenticated user from a request. Returns undefined when the request is unauthenticated. This method is optional on the contract.

const user = await authService.getCurrentUser?.(request);
if (user) {
  console.log(`Request from ${user.name} (${user.positions?.join(', ')})`);
}

AuthSession Interface

export interface AuthSession {
  /** Session identifier */
  id: string;
  /** Associated user identifier */
  userId: string;
  /** Session expiry (ISO 8601) */
  expiresAt: string;
  /** Bearer token (if not using cookies) */
  token?: string;
}

AuthResult

verify resolves to an AuthResult. On success it carries the user and session; on failure error holds a message string.

export interface AuthResult {
  /** Whether authentication succeeded */
  success: boolean;
  /** Authenticated user (if success) */
  user?: AuthUser;
  /** Active session (if success) */
  session?: AuthSession;
  /** Error message (if failure) */
  error?: string;
}

On this page