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.
| Property | Description |
|---|
ctx.user.userId | Unique user identifier |
ctx.user.email | User’s email address |
ctx.user.name | Display name |
ctx.user.groups | Array of group names the user belongs to |
ctx.user.metadata | Custom 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:
| Layer | What it does | Example |
|---|
| Backend API | Filters data and blocks unauthorized actions using ctx.user | Only return orders where owner_email matches the current user |
| Frontend | Hides or disables UI elements for a better experience | Hide 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
| Tip | Why |
|---|
Name the specific group (e.g., "admin", "finance-viewers") | Clark uses the exact group name in the check |
| Mention both backend and frontend behavior | Clark 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: