langflow-ai/langflow · error · HTTPException

Only the resource owner or a superuser may administer shares

Error message

Only the resource owner or a superuser may administer shares for this resource.

What it means

Raised by _ensure_can_administer_share in the /api/v1/authz/shares routes — the OSS ownership floor. If the caller is neither the resource owner nor a superuser and no cross-user-fetch-capable authorization plugin is active, share administration is refused with 403. When a plugin signals supports_cross_user_fetch() AND is_enabled(), this floor is bypassed and the plugin's ensure_share_permission() becomes the authoritative gate.

Source

Thrown at src/backend/base/langflow/api/v1/authz_shares.py:196

    owner_id: UUID | None,
) -> None:
    """Require resource owner or superuser unless cross-user enforcement is active."""
    if getattr(user, "is_superuser", False):
        return
    if owner_id is not None and owner_id == user.id:
        return
    authz = get_authorization_service()
    if await authz.supports_cross_user_fetch() and await authz.is_enabled():
        # Why: in OSS, ``supports_cross_user_fetch()`` is False (see
        # LangflowAuthorizationService), so this early-return is dead and the
        # explicit 403 below is the floor. When an authorization plugin signals
        # cross-user fetch support, the plugin is the authoritative gate via
        # the ``ensure_share_permission()`` call that every share route makes
        # immediately after this helper. Removing that downstream call — or
        # weakening the plugin's cross-user fetch contract — REOPENS the
        # ownership gap. Keep the two in lockstep.
        return
    raise HTTPException(
        status_code=status.HTTP_403_FORBIDDEN,
        detail="Only the resource owner or a superuser may administer shares for this resource.",
    )


@router.post("", response_model=ShareRead, status_code=status.HTTP_201_CREATED)
@router.post("/", response_model=ShareRead, status_code=status.HTTP_201_CREATED)
async def create_share(
    payload: ShareCreate,
    current_user: CurrentActiveUser,
    session: DbSession,
) -> ShareRead:
    """Create an authz_share row for a resource."""
    owner_id = await _resolve_resource_owner(
        session,
        resource_type=payload.resource_type,
        resource_id=payload.resource_id,
    )

View on GitHub (pinned to 976ec789d2)

Solutions

  1. Perform share administration as the resource owner or as a superuser
  2. Install/register an authorization plugin via the lfx.services entry point (authorization_service) that sets SUPPORTS_CROSS_USER_FETCH=True and grants share permissions
  3. Do not attempt to bypass the floor — it exists so the OSS pass-through cannot let a non-owner mint share rows
Defensive patterns

Strategy: validation

Validate before calling

async function canAdministerShares(user, ownerId) {
  return user.is_superuser || user.id === ownerId;
}

Type guard

const canAdminShares = (u: {id: string; is_superuser: boolean}, ownerId: string): boolean =>
  u.is_superuser || u.id === ownerId;

Prevention

When it happens

Trigger: POST/PATCH/DELETE /api/v1/authz/shares/{id} (or POST /authz/shares) as a non-owner, non-superuser while running the OSS pass-through authorization service (LANGFLOW_AUTHZ_ENABLED=false or no plugin registered).

Common situations: Team admin trying to manage another user's shares on OSS Langflow (no plugin installed); enabling LANGFLOW_AUTHZ_ENABLED=true but expecting it to widen share administration — without a registered plugin the floor stays; scripts using service accounts that are not superusers.

Related errors


AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14). Data as JSON: /api/errors/663cf5a3d8a3d1e6. Report an issue: GitHub.