Skip to content
Console →
Website →
Asking an AI? Paste this URL https://keelson.dev/llms.txt

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 doWhat to useAdditional setup
Identify who is accessing the app (record the creator, show only the user’s own data)Headers X-Keelson-User-Id / -Email / -NameNone
Create a screen that only managers can seeHeader X-Keelson-User-App-PermsNone (permissions are set in the console)
Use three or more permission levels or branch by groupIdentity SDK attributes.groupskeelson apps directory enable

Keelson adds headers to authenticated requests.

HeaderContents
X-Keelson-User-IdUser ID (a stable identifier; use this when storing the user in a database)
X-Keelson-User-EmailEmail address (empty if the user has no email address in Keelson)
X-Keelson-User-NameDisplay name (empty if the user has no display name in Keelson)
# FastAPI / Flask
user_id = request.headers.get("X-Keelson-User-Id")
email = request.headers.get("X-Keelson-User-Email")
// Express
const 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 }

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-PermsMeaning
viewCan view
view,manageCan 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 perms

This 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.

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.

Terminal window
keelson apps directory enable
keelson deploy

This 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, and everyone; Admin belongs to admins, developers, and everyone; Developer belongs to developers and everyone; App User belongs to everyone
  • 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).

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.

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.