MisarMisar Docs
MisarMailMisar.BlogMisarReachMisarPostMisar.DevMisarSEOMisar PlatformMisar SSO
Workspaces

Access Check

The membership check other Misar products call to gate a workspace's data.

GET/io/workspaces/access

Resolves whether a user has access to a workspace and, if so, their effective role. This is the endpoint products call to gate a workspace — check allowed before serving that workspace's data. Accepts either service-key or SSO bearer auth.

Query parameters

workspace_idstringqueryrequired

The workspace UUID to check.

user_idstringquery

The acting user's UUID. Required with service-key auth. With bearer auth it defaults to the token subject and, if supplied, must match it.

Response fields

allowedboolean

true when the user owns the workspace or holds an active membership.

role"owner" | "admin" | "member" | null

The effective role, or null when the user has no access.

GET https://api.misar.io/io/workspaces/access?workspace_id=6f1e9c2a-1b3d-4c5e-8f90-a1b2c3d4e5f6&user_id=usr-uuid
x-workspace-service-key: <WORKSPACE_SERVICE_KEY>
{ "data": { "allowed": true, "role": "admin" } }
{ "data": { "allowed": false, "role": null } }

Enforcing access in a product

A product should call this endpoint (or the SDK's checkAccess) inside its request-auth layer, before serving any workspace-scoped data. Deny the request when allowed is false.

import { createWorkspaceClient } from "@misar/workspace";

const workspaces = createWorkspaceClient({
  baseUrl: "https://api.misar.io/io/workspaces",
  serviceKey: process.env.WORKSPACE_SERVICE_KEY,
});

/**
 * Throws a 403 unless the user can access the workspace.
 * Returns the resolved role so callers can gate admin-only actions.
 */
export async function requireWorkspaceAccess(userId: string, workspaceId: string) {
  const { allowed, role } = await workspaces.checkAccess(userId, workspaceId);
  if (!allowed) {
    throw new Response("Forbidden", { status: 403 });
  }
  return role; // "owner" | "admin" | "member"
}

A misconfigured server (missing Supabase env) fails as 500, not a silent { allowed: false }. Treat a network/5xx error as "unknown", not "denied", and surface it rather than leaking data.

Status codes

CodeMeaning
200Check completed — see data.allowed / data.role
400A valid workspace_id is required or Invalid user_id
401Unauthorized — missing/invalid auth
500Internal server error (e.g. misconfigured backend)