How Kaneo Handles Authentication and Authorization: A Complete Technical Guide
Kaneo implements a secure, multi-method authentication system using the Better-Auth library combined with workspace-scoped role-based access control (RBAC) for granular authorization.
The open-source project management platform usekaneo/kaneo delegates its entire security stack to Better-Auth, adding a custom permission layer that treats each workspace as an isolated organization. This architecture enables flexible identity verification while enforcing strict access boundaries between projects.
Core Authentication Flow
The authentication lifecycle in Kaneo begins in apps/api/src/auth.ts, where the Better-Auth instance is configured with enterprise-grade security defaults and multiple identity providers.
Better-Auth Instance Configuration
The central authentication object is exported from apps/api/src/auth.ts and mounted under the /api/auth route prefix. The configuration uses the Drizzle adapter to persist sessions and user data to PostgreSQL.
export const auth = betterAuth({
database: drizzleAdapter(db),
secret: process.env.AUTH_SECRET, // Must be ≥32 characters
trustedOrigins: [process.env.APP_URL],
// ... plugins and hooks
});
The AUTH_SECRET environment variable protects signed cookies and must be at least 32 characters long. The trustedOrigins array restricts cookie transmission to specific domains, preventing cross-site request forgery.
Session Management and Security
Sessions are stored in the database with a short-lived cookie cache to minimize lookup overhead. According to the source code in apps/api/src/auth.ts, the session configuration uses:
maxAge: 5 * 60(5 minutes) for cookie cache duration- Secure, SameSite attributes derived from
getDefaultCookieAttributes - Automatic cache refresh after each successful authentication
This design reduces database load while maintaining security through frequent re-validation.
Supported Authentication Methods
Kaneo supports seven distinct authentication strategies via the Better-Auth plugin system:
- Anonymous – Guest accounts with
emailDomainNameset tokaneo.app - Magic Link – Passwordless email-based tokens
- Email OTP – One-time verification codes
- Social Providers – GitHub, Google, Discord, and custom OAuth integrations
- Bearer – Standard
Authorization: Bearer <token>headers for external services - API Key – Header-based authentication using
x-api-key - Device Authorization – OAuth-like flow for CLI tools
Password registration is optional and controlled via the DISABLE_PASSWORD_REGISTRATION environment variable. When enabled, the emailAndPassword plugin validates credentials against the PostgreSQL user table.
Bootstrap and Rate Limiting
The first user to register is automatically promoted to instance-wide admin through a database hook (hooks.databaseHooks.user.create.after) protected by a PostgreSQL advisory lock to prevent race conditions.
Rate limiting is configured with a global 10-second window and custom rules for sign-up and invitation endpoints. In cloud deployments, Turnstile verification protects the registration flow by validating client tokens before account creation.
Authorization and Workspace Access Control
Kaneo treats each workspace as an independent organization with isolated permission boundaries. Authorization logic resides in packages/permissions/src/index.ts and integrates with Better-Auth's organization plugin.
Role-Based Permission Statements
The system defines four default roles with cascading privileges:
- viewer – Read-only access to projects, tasks, labels, and workspace settings
- member – Create/read projects; create/read/update tasks; full label CRUD
- admin – Full CRUD on projects, tasks, and labels; includes
manage_settingspermission - owner – Identical to admin but with immutable role assignment
These roles are instantiated using Better-Auth's access control (AC) statements:
// From packages/permissions/src/index.ts
export const admin = ac.newRole({
project: ["create", "read", "update", "delete"],
task: ["create", "read", "update", "delete"],
// ...
});
The permissions package exports an ac instance that evaluates whether a user's role satisfies required actions for specific resources.
Route Protection and Permission Checks
API routes protect resources using a requireWorkspacePermission middleware wrapper. This function validates the caller's session, extracts their workspace role from the workspace_user table, and queries the ac evaluator before allowing execution.
import { requireWorkspacePermission } from "@kaneo/permissions";
export const updateTask = createRoute({
method: "post",
path: "/tasks/:id",
middleware: [requireWorkspacePermission("task", "update")],
// ... handler
});
The organization plugin exposes CRUD operations under /auth/organization/* for managing members, teams, and invitations, documented via the OpenAPI spec generated in apps/api/src/auth-openapi.ts.
API Security and Advanced Features
Beyond standard session cookies, Kaneo provides machine-to-machine authentication and extensible OAuth integrations.
API Keys and Bearer Tokens
The API Key plugin (apiKey) enables service accounts to authenticate via the x-api-key header. Keys can be configured to create temporary sessions (enableSessionForAPIKeys: true) or operate statelessly. The Bearer plugin supports standard OAuth 2.0 bearer tokens for third-party integrations.
Both methods respect the global rate-limiting configuration defined in apps/api/src/auth.ts and appear in the automatically generated OpenAPI documentation.
Rate Limiting and Abuse Protection
Rate limiting applies a 10-second window to all authentication endpoints, with stricter limits on high-risk operations like sign-up. The cloud deployment enables Turnstile (Cloudflare) challenge verification to prevent automated abuse.
Anonymous Guest Access
When DISABLE_GUEST_ACCESS is unset, anonymous users receive temporary accounts with viewer-level permissions. A pre-authentication hook (hooks.before) blocks anonymous users from accessing /organization/invite-member to prevent privilege escalation.
Custom OAuth and SSO
The genericOAuth plugin enables SSO without code changes by reading CUSTOM_OAUTH_* environment variables. Administrators configure the client ID, secret, token URL, and user-info mapping via mapCustomOAuthProfileToUser in apps/api/src/auth.ts.
Summary
- Kaneo delegates authentication to Better-Auth with a centralized configuration in
apps/api/src/auth.ts, supporting seven login methods including social, passwordless, and API keys. - Authorization uses workspace-scoped RBAC defined in
packages/permissions/src/index.ts, with four default roles (viewer, member, admin, owner) that control access to projects and tasks. - Sessions are cached in short-lived cookies (5 minutes) with secure attributes, while the first registered user automatically receives instance admin privileges.
- Machine authentication supports both API keys (
x-api-keyheader) and Bearer tokens for external service integration. - Security hardening includes rate limiting, Turnstile verification, and PostgreSQL advisory locks for race-sensitive operations like initial user creation.
Frequently Asked Questions
How does Kaneo store and validate user sessions?
Kaneo stores session data in PostgreSQL via the Drizzle adapter and caches active sessions in cookies with a 5-minute TTL. The session.cookieCache.enabled setting in apps/api/src/auth.ts ensures the database is queried only when the cache expires or after authentication events. Cookies use secure, SameSite attributes derived from getDefaultCookieAttributes.
Can I disable password-based registration in Kaneo?
Yes. Set the DISABLE_PASSWORD_REGISTRATION environment variable to remove the emailAndPassword plugin from the Better-Auth configuration. When disabled, users must authenticate via magic links, social providers, API keys, or other supported methods. The check occurs during the auth instance initialization in apps/api/src/auth.ts.
How are workspace permissions enforced in API routes?
Routes use the requireWorkspacePermission middleware imported from @kaneo/permissions. This wrapper extracts the user's role from their workspace_user record and evaluates it against the access-control statements defined in packages/permissions/src/index.ts. If the role lacks the required action (e.g., task:update), the middleware returns a 403 before the route handler executes.
What authentication methods are available for CLI or API integrations?
Kaneo supports two machine-to-machine methods: API Keys (via the x-api-key header with optional session creation) and Bearer Tokens (via the Authorization: Bearer header). Both are implemented as Better-Auth plugins in apps/api/src/auth.ts and include rate-limiting protection. The OAuth Device Authorization flow in apps/api/src/mcp/oauth.ts also enables CLI authentication through user-verified device codes.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →