Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.superblocks.com/llms.txt

Use this file to discover all available pages before exploring further.

Clark builds secure access control into your app by default. When you describe who should see what, Clark puts authorization checks in the right place, filtering data in backend APIs using the authenticated user’s identity and adjusting the UI to match. This guide covers the concepts behind in-app access control and how to prompt Clark to build it into your app.

How it works

User identity

Every backend API in Superblocks has access to the current user’s identity through ctx.user. This is populated from the authenticated session and can’t be modified by the end user or passed in from the frontend.
PropertyDescription
ctx.user.userIdUnique user identifier
ctx.user.emailUser’s email address
ctx.user.nameDisplay name
ctx.user.groupsArray of group names the user belongs to
ctx.user.metadataCustom metadata passed via embed session tokens (embedded apps only)
When you ask Clark to restrict access, it uses ctx.user in backend API code to gate access or filter data. This is the secure path because the identity comes from the server, not the browser.

Groups

Groups are the main building block for access control. They map to your identity provider (Okta, Azure AD, etc.) via SCIM sync, or can be managed manually in Organization Settings. For example, a user in the "finance-admins" group might see all invoices, while a user in "finance-viewers" can only see their own department’s records.

Backend vs. frontend checks

Clark enforces access control in two layers:
LayerWhat it doesExample
Backend APIFilters data and blocks unauthorized actions using ctx.userOnly return orders where owner_email matches the current user
FrontendHides or disables UI elements for a better experienceHide the “Delete” button for non-admins
Backend checks are the security boundary. Frontend checks improve the experience by not showing users things they can’t access. Clark builds both layers when you describe the behavior you want.

What Clark generates

When you prompt Clark with access control requirements, it generates code like the following. Backend — gating an entire API:
async run(ctx) {
  if (!ctx.user.groups.includes("admin")) {
    throw new Error("Access denied: admin group required");
  }

  // ... rest of the API logic
}
Backend — filtering data by user identity:
async run(ctx) {
  const orders = await ctx.integrations.db.query(
    "SELECT * FROM orders WHERE owner_email = $1",
    OrderSchema,
    [ctx.user.email]
  );

  return { orders };
}
Frontend — conditional rendering based on group:
const isAdmin = user?.groups?.includes("admin");

if (!isAdmin) {
  return <p>You don't have access to this page.</p>;
}
You don’t need to write any of this yourself. Clark generates it from your prompt. These examples are here so you can recognize what Clark built and understand what it’s doing.

Common patterns

Role-gated API access

Restrict an entire API to users in a specific group. If the user isn’t in the group, the API returns an error before accessing any data. Good for: Admin dashboards, sensitive operations (delete, export), management tools.

Row-level security

Filter query results using ctx.user.email or ctx.user.userId so users only see their own data. Good for: Multi-tenant apps, “my orders” views, user-specific dashboards.

Feature-level gating

Return different fields or allow different mutations depending on the user’s group, without blocking the entire API. Good for: APIs that serve multiple roles (viewers see read-only data, editors can update).

Frontend conditional rendering

Hide buttons, tabs, or pages for users who don’t have access. Clark pairs this with backend enforcement automatically. Good for: Navigation menus, action buttons, admin-only sections.

How to prompt Clark

Describe who and what

Tell Clark which group should have access and what they should (or shouldn’t) see. Be specific about group names.
Build an orders page. Admins (users in the 'admin' group) should see all
orders. Regular users should only see their own orders. On the frontend,
hide the 'Export All' button for non-admins.
Clark will build the backend API with ctx.user checks, filter the data query, and conditionally render the button, all from this single prompt.

More examples

Gating an API:
Only allow users in the 'admin' group to access this API. If they're not
an admin, throw an access denied error.
Row-level security:
Filter the orders query so users can only see orders where the owner_email
matches their own email.
Multi-level access:
Users in the 'manager' group can see all records in their department.
Regular users can only see their own.
Frontend UX:
Show an 'Admin Settings' tab in the sidebar only for users in the
'org-admins' group.
If the user doesn't have the 'editor' group, make the form fields
read-only instead of hiding them.

Tips for better results

TipWhy
Name the specific group (e.g., "admin", "finance-viewers")Clark uses the exact group name in the check
Mention both backend and frontend behaviorClark builds the full pattern: API enforcement + UI polish

Setting up groups

For in-app access control to work, your users need to be in the right groups: