Skip to content

[bug] host-cloudflare: AccountProvider.me omits orgRole, so the console hides every workspace mutation from admins #1958

Description

@BobzTH

Executor version: v1.6.8
Surface: self-hosted on Cloudflare Workers (apps/host-cloudflare), behind Cloudflare Access
Integration: any workspace-owned connection (observed on cloudflare-api, cloudflare-bindings)

What happened

After upgrading to v1.6.8, an administrator (email listed in ADMIN_EMAILS) can no longer perform any workspace mutation from the console. On a workspace-owned connection the row menu offers only Check now — Edit, Reconnect and Remove are all hidden. Personal connections keep the full menu.

The server does not agree with the UI. From the same authenticated browser session:

POST /api/oauth/start  {"clientOwner":"org","owner":"org","integration":"cloudflare-api",...}
→ 200 {"status":"redirect","authorizationUrl":"https://..."}

So the principal is an admin and the API authorises the write. Only the console hides it.

Cause

principalFromAccessClaims computes the role correctly (apps/host-cloudflare/src/auth/cloudflare-access.ts):

const isAdmin = email.length > 0 && config.adminEmails.includes(email.toLowerCase());
orgRole: isAdmin ? "admin" : "member",

But AccountProvider.me (apps/host-cloudflare/src/account/account-provider.ts) never returns it:

me: (headers) => ... Effect.succeed({
  user: { id, email, name, avatarUrl },
  organization: { id, name, slug },
})   // no orgRole / orgRoleModel

Confirmed against a live deployment — GET /api/account/me returns the correct email and organization, and no role field of any kind.

Per #1919, "Missing role data under the organization model fails closed", so the console treats every principal as a member and hides workspace mutations from everyone, admins included. Cloud derives roles from WorkOS and self-host from Better Auth; the Cloudflare host appears to have been missed.

What I expected

AccountProvider.me on host-cloudflare should surface orgRole (and orgRoleModel) from the verified Access principal, so the console can enable workspace mutations for admins — matching the cloud and self-host behaviour.

Steps to reproduce

  1. Deploy apps/host-cloudflare at v1.6.8 behind Cloudflare Access, with ADMIN_EMAILS=you@example.com.
  2. Sign in through Access with that exact email.
  3. GET /api/account/me → your email and organization are correct; no role is returned.
  4. Open an integration that has a workspace connection → its row menu shows only Check now.
  5. POST /api/oauth/start with owner: "org" from that same session → 200 with an authorizationUrl, proving the server treats you as an admin.

The practical effect is that an expired workspace OAuth connection cannot be repaired through the UI at all, because Reconnect and Remove are both hidden. Rolling the Worker back to the pre-1.6.8 version restores the buttons.

Related note (possibly separate)

Cloudflare Access service tokens authenticate with common_name and carry no email, so isAdmin can never be true for them — the unit test asserts this directly (// a token is a member, not an admin). On an Access-gated single-tenant deployment this means every machine identity permanently loses workspace writes, including executor.mcp.addServer and connection reconnects from inside execute. An ADMIN_COMMON_NAMES allowlist alongside ADMIN_EMAILS would restore that; happy to open it as a separate feature request if you'd prefer.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions