Use identity in your app
Keelson handles sign-in and permission checks, so your app does not need authentication code. The app only reads the information added by Keelson and changes its behavior based on who the user is and what they can do.
There are three levels, depending on what you need.
| What you want to do | What to use | Additional setup |
|---|---|---|
| Identify who is accessing the app (record the creator, show only the user’s own data) | Headers X-Keelson-User-Id / -Email / -Name | None |
| Create a screen that only managers can see | Header X-Keelson-User-App-Perms | None (permissions are set in the console) |
| Use three or more permission levels or branch by group | Identity SDK attributes.groups | keelson apps directory enable |
1. Identify who is accessing the app
Section titled “1. Identify who is accessing the app”Keelson adds headers to authenticated requests.
| Header | Contents |
|---|---|
X-Keelson-User-Id | User ID (a stable identifier; use this when storing the user in a database) |
X-Keelson-User-Email | Email address (empty if the user has no email address in Keelson) |
X-Keelson-User-Name | Display name (empty if the user has no display name in Keelson) |
# FastAPI / Flaskuser_id = request.headers.get("X-Keelson-User-Id")email = request.headers.get("X-Keelson-User-Email")// Expressconst userId = req.headers["x-keelson-user-id"];const email = req.headers["x-keelson-user-email"];The proxy adds these headers. Authorization, Cookie, and headers with the same names sent by the browser are removed before reaching the app, so they cannot be spoofed. The app does not manage sessions itself.
The Identity SDK lets you read the headers with types and requires no network access.
import { getCurrentUser } from "@keelsonhq/identity";const user = getCurrentUser({ headers: req.headers }); // { id, email, name }2. Create a manager-only screen
Section titled “2. Create a manager-only screen”An app has two permissions: view and manage. Assign them to groups in the console or CLI (Groups and app access). Keelson passes the result in a header.
X-Keelson-User-App-Perms | Meaning |
|---|---|
view | Can view |
view,manage | Can view and manage |
The app only checks whether manage is included. Do not put group names in the code.
const perms = (req.headers["x-keelson-user-app-perms"] ?? "").split(",");const canManage = perms.includes("manage");app.get("/admin", (req, res) => { if (!canManage) return res.status(403).end(); ...});perms = request.headers.get("X-Keelson-User-App-Perms", "").split(",")can_manage = "manage" in permsThis level supports cases such as an app only for the accounting team or a settings screen only for managers. You can change who has manage in the console without changing the code.
3. Branch by group
Section titled “3. Branch by group”If you need three or more permission levels or group-based branching, use the Identity SDK to retrieve the user’s groups.
Allow the app to read the Directory API, then redeploy it.
Enabling Directory access stores the token, but it is not injected into the app until you redeploy.
keelson apps directory enablekeelson deployThis injects KEELSON_DIRECTORY_TOKEN into the app, and the SDK uses it automatically. Use the token only on the server; do not pass it to the browser.
import { getCurrentIdentity } from "@keelsonhq/identity";
const me = await getCurrentIdentity({ headers: req.headers });const groups = me.attributes?.groups ?? []; // Example: ["everyone", "developers", "accounting"]if (groups.includes("accounting")) { ... }from keelson_identity import get_current_identity
me = get_current_identity(headers=request.headers)groups = me.attributes.groups if me.attributes else []if "accounting" in groups: ...attributes.groups contains group keys.
- Role-based system groups: Owner belongs to
owners,developers, andeveryone; Admin belongs toadmins,developers, andeveryone; Developer belongs todevelopersandeveryone; App User belongs toeveryone - Custom groups that the user belongs to and that have permission for this app. Groups that are not assigned to the app are not included
- Keys do not change, so you can use them in code for checks. Non-ASCII keys such as
経理are also supported
The return value of getCurrentIdentity also contains the user (id, email, name), their workspace role (workspace.role), and their permissions for this app (app.permissions).
List members
Section titled “List members”When you need information about other members, such as options for an assignee field, use listMembers / list_members (with search and filtering by role or group), getUser, and listGroups.
Local development
Section titled “Local development”The Identity SDK returns a dummy user when KEELSON_LOCAL_MODE=1. Change the values with KEELSON_LOCAL_USER_ID, KEELSON_LOCAL_USER_EMAIL, KEELSON_LOCAL_WORKSPACE_ROLE, and related variables. Code that reads only the headers must account for None / undefined because the headers are absent during local development.
Requests without sign-in, such as webhooks
Section titled “Requests without sign-in, such as webhooks”Paths called by external systems (auth.endpoints) do not receive X-Keelson-User-Id. Authenticate these requests with a webhook signature or app token. See External integrations.
Related pages
Section titled “Related pages”- Groups and app access — choose who receives view / manage
- Authentication and login