How Multi-Organization Delegated Auth Works in OpenSEO: A Technical Deep Dive

OpenSEO implements multi-organization delegated authentication by creating a deterministic, user-specific organization (format delegated-${userId}) for each delegated auth session, allowing users to maintain separate hosted organizations while ensuring every delegated request operates within an isolated workspace.

OpenSEO's architecture supports both hosted authentication and delegated authentication modes (such as Cloudflare Access or local development) within a single codebase. Understanding how multi-organization delegated auth works in OpenSEO requires examining the middleware layer that resolves user contexts and the repository pattern that maintains organization isolation. This implementation ensures that users authenticating via delegated methods receive a dedicated organization while preserving their ability to belong to multiple organizations across different authentication modes.

Core Architecture of Delegated Authentication

The Delegated Organization Pattern

When a user authenticates via a delegated provider, the system cannot rely on pre-existing organization memberships from hosted auth. Instead, OpenSEO generates a unique organization identifier using the pattern delegated-${userId}. This deterministic ID ensures consistency across requests while creating a sandboxed environment for the user's data.

User Record Guarantee

Before creating the delegated organization, the middleware ensures a valid user record exists in the database. The ensureUserRecord function validates or creates the user entity, providing the necessary foreign key for subsequent organization membership operations.

Implementation Flow

Resolving the Delegated Context

The entry point for delegated authentication resides in src/middleware/ensure-user/delegated.ts. The resolveDelegatedContext function orchestrates the entire flow by first validating the user record, then provisioning the dedicated organization:

// src/middleware/ensure-user/delegated.ts
export async function resolveDelegatedContext(
  userId: string,
  userEmail: string,
): Promise<EnsuredUserContext> {
  const ensuredEmail = await ensureUserRecord(userId, userEmail);
  const organizationId = await ensureDelegatedOrganizationForUser(
    userId,
    ensuredEmail,
  );

  return {
    userId,
    userEmail: ensuredEmail,
    emailVerified: true,
    organizationId, // Format: `delegated-${userId}`
  };
}

Generating the Organization Identity

The ensureDelegatedOrganizationForUser function in src/server/auth/delegated-organization.ts constructs the organization metadata. It derives a human-readable name from the email prefix and generates a URL-safe slug combined with a hexadecimal representation of the user ID:

// src/server/auth/delegated-organization.ts
export async function ensureDelegatedOrganizationForUser(
  userId: string,
  email: string,
) {
  const organizationId = `delegated-${userId}`;
  const name = `${email.split("@")[0] || userId} workspace`;
  const slug = `delegated-${slugify(email.split("@")[0] || userId)}-${toHex(
    userId,
  )}`;

  await AuthRepository.upsertDelegatedOrganization({
    id: organizationId,
    name,
    slug,
  });

  return organizationId;
}

Persisting the Organization Record

The AuthRepository class in src/server/auth/repositories/AuthRepository.ts provides the upsertDelegatedOrganization method. This performs an atomic insert-or-update operation against the organization table, ensuring idempotency across multiple requests:

// src/server/auth/repositories/AuthRepository.ts
async function upsertDelegatedOrganization(input: {
  id: string;
  name: string;
  slug: string;
}) {
  await db
    .insert(organization)
    .values({
      id: input.id,
      name: input.name,
      slug: input.slug,
      logo: null,
      createdAt: new Date(),
      metadata: null,
    })
    .onConflictDoUpdate({
      target: organization.id,
      set: { name: input.name, slug: input.slug },
    });
}

Multi-Organization Membership Support

Despite the automatic creation of a delegated organization, OpenSEO maintains full multi-organization capabilities through the member table. This many-to-many relationship table stores all organization memberships, allowing a single user to belong to numerous hosted organizations simultaneously.

When processing delegated requests, the system explicitly sets the organizationId in the EnsuredUserContext to the user-specific delegated organization. This isolation prevents data leakage between organizations while the underlying findFirstOrganizationIdForUser query (used in hosted contexts) continues to respect the user's broader membership portfolio. The architecture effectively partitions delegated sessions into their own workspaces without restricting the user's ability to access other organizations through different authentication flows.

Summary

  • OpenSEO creates a deterministic organization ID using the pattern delegated-${userId} for every delegated authentication session.
  • The resolveDelegatedContext function in src/middleware/ensure-user/delegated.ts orchestrates user validation and organization provisioning.
  • ensureDelegatedOrganizationForUser generates human-readable names and URL-safe slugs based on user email and ID.
  • AuthRepository.upsertDelegatedOrganization performs atomic upserts to maintain idempotency.
  • The member table preserves multi-organization relationships, allowing users to maintain separate hosted organizations while using delegated auth.

Frequently Asked Questions

What is the format of the delegated organization ID?

OpenSEO uses the format delegated-${userId} to generate a unique, deterministic organization identifier for each user accessing the system via delegated authentication. This ensures the same user always receives the same organization ID across sessions while maintaining isolation from other users.

Can a user belong to multiple organizations while using delegated auth?

Yes. The delegated organization is created in addition to any existing memberships in the member table. Users can belong to multiple hosted organizations while the delegated auth flow automatically provisions a dedicated workspace for their current session, with the organizationId explicitly set in the context to ensure proper data isolation.

How does the system handle concurrent delegated auth requests?

The upsertDelegatedOrganization method uses database-level conflict resolution with onConflictDoUpdate, making the operation idempotent. Whether the organization already exists or needs creation, the repository method ensures consistent state without duplicate records or race conditions.

Where is the delegated organization created in the codebase?

The creation flow spans three primary files: src/middleware/ensure-user/delegated.ts initiates the context resolution, src/server/auth/delegated-organization.ts generates the organization metadata, and src/server/auth/repositories/AuthRepository.ts persists the record to the database.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →