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

Run your app locally

When you run your app on your machine, there is no Keelson login, so requests carry no user information headers such as X-Keelson-User-Id. With keelson dev serve, your app receives the same headers as on Keelson, and you can switch between users to check its behavior.

Through keelson dev serveKEELSON_LOCAL_MODE=1 (no CLI)
UserSwitch to anyone in the user listOne fixed user
How user information arrivesThe same headers as in productionThe SDK returns test data (no headers)
Member list and groups (listMembers and so on)Returned from the user list (no need to enable the Directory API)Returned from the user list
RequiresThe latest Keelson CLIThe latest SDK

Use keelson dev serve normally. If the CLI is not installed, or only an older CLI is available, start with KEELSON_LOCAL_MODE=1. Your app code is the same either way.

After --, write the command that starts your app’s server.

Terminal window
# Node.js
keelson dev serve -- node server.js
# Python
keelson dev serve -- uvicorn main:app --host 127.0.0.1 --port {port}
# Go
keelson dev serve -- go run .
  • The CLI picks a free port for your app and passes it in the PORT environment variable. It also replaces {port} in the command with that number. Your app must listen on that port on 127.0.0.1
  • Open http://localhost:5173/ in your browser. Change the port with --port
  • The CLI sits in front of your app and adds the selected user’s headers (X-Keelson-User-Id / X-Keelson-User-Email / X-Keelson-User-Name / X-Keelson-User-App-Perms) to every request. As in production, the browser’s cookies and Authorization header do not reach your app
  • On startup, the CLI prints the app URL, the current user, and how to switch users. Press Ctrl-C to stop it; your app’s server stops too
MethodHow to use it
Switch pageOpen http://localhost:5173/__keelson/dev in your browser and choose a user. Other open tabs keep the previous user until you reload them
X-Keelson-Dev-As headerAdd X-Keelson-Dev-As: <user ID> to a request to act as that user for that request only. Use it when testing with AI agents or curl
--asRun keelson dev serve --as <user ID> -- ... to choose the user at startup
Terminal window
# Call the API as a user with view permission only
curl -H "X-Keelson-Dev-As: local-user-003" http://localhost:5173/api/items

An ID that is not in the user list returns an error.

Provide the list of users as a JSON file. It is looked up in this order:

  • keelson dev serve: --users <file> → ./.keelson/dev-users.json
  • KEELSON_LOCAL_MODE=1: the KEELSON_LOCAL_USERS_FILE environment variable → ./.keelson/dev-users.json
{
"users": [
{ "id": "sample-alice", "email": "[email protected]", "name": "Alice Smith", "perms": ["view", "manage"] },
{ "id": "sample-bob", "email": "[email protected]", "name": "Bob Jones", "perms": ["view"] }
]
}
FieldContent
idUser ID. Must be unique within the list. Any readable string works; it does not need to match production IDs
email / nameEmail address and display name. Empty strings are allowed
perms["view"] (view only) or ["view", "manage"] (with manage permission). Becomes the value of X-Keelson-User-App-Perms
image_urlOptional. Profile image URL
  • The first user in the list with manage is the default user
  • If the specified file is missing or invalid, startup fails with an error
  • Without a user list file, four built-in users (local-user-001 to local-user-004) are used. With keelson dev serve, local-user-003 and local-user-004 have view permission only
  • Restart after changing the user list

Run without the CLI (KEELSON_LOCAL_MODE=1)

Section titled “Run without the CLI (KEELSON_LOCAL_MODE=1)”

Start your app’s server directly with the KEELSON_LOCAL_MODE=1 environment variable.

Terminal window
KEELSON_LOCAL_MODE=1 node server.js

If your app uses its own user list with keelson dev serve --users <file>, also pass KEELSON_LOCAL_USERS_FILE=<same file> when you start it directly. User IDs then stay the same with or without the CLI.

The Identity SDK does not read headers and returns one fixed user (the first user in the list with manage) as the current user. Without a user list file, it returns a test user with manage permission (local-user-001). You cannot switch users. This test data does not apply to code that reads headers directly.

Get the current user and permissions (getRequestUser)

Section titled “Get the current user and permissions (getRequestUser)”

getRequestUser returns the current user and their permissions for this app (perms) from the request headers in one call. It makes no external request. The same code works in production and in both local modes above.

import { getRequestUser } from "@keelsonhq/identity";
app.get("/admin", async (req, res) => {
const user = await getRequestUser({ headers: req.headers }); // { id, email, name, perms }
if (!user.perms.includes("manage")) return res.status(403).end();
res.send(`Hello, ${user.name ?? user.id}`);
});
from keelson import identity
user = identity.get_request_user(headers=request.headers)
if "manage" not in user.perms:
... # Return 403
client, err := identity.New("") // Once at startup
// Inside the handler
user, err := client.GetRequestUser(identity.WithHeaders(r.Header))
if err != nil {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
canManage := slices.Contains(user.Perms, "manage")

A missing user ID header raises an error. perms is X-Keelson-User-App-Perms split into a list, or empty when the header is absent. Display names in non-ASCII scripts, such as Japanese, are read correctly.

These local development features do not work in an app deployed on Keelson.

  • If KEELSON_LOCAL_MODE is set in a deployed app, the SDK raises an error instead of returning test data. Remove KEELSON_LOCAL_MODE
  • keelson dev serve also refuses to start in a deployed environment