# How Kaneo Handles Authentication and Authorization: A Complete Technical Guide

> Discover how Kaneo handles authentication and authorization with its multi-method system and workspace-scoped RBAC for secure, granular access control. Explore the technical guide.

- Repository: [kaneo.app/kaneo](https://github.com/usekaneo/kaneo)
- Tags: deep-dive
- Published: 2026-08-30

---

**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](https://github.com/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`](https://github.com/usekaneo/kaneo/blob/main/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`](https://github.com/usekaneo/kaneo/blob/main/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.

```typescript
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`](https://github.com/usekaneo/kaneo/blob/main/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 `emailDomainName` set to `kaneo.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`](https://github.com/usekaneo/kaneo/blob/main/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_settings` permission
- **owner** – Identical to admin but with immutable role assignment

These roles are instantiated using Better-Auth's access control (AC) statements:

```typescript
// 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.

```typescript
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`](https://github.com/usekaneo/kaneo/blob/main/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`](https://github.com/usekaneo/kaneo/blob/main/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`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/auth.ts).

## Summary

- **Kaneo delegates authentication** to Better-Auth with a centralized configuration in [`apps/api/src/auth.ts`](https://github.com/usekaneo/kaneo/blob/main/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`](https://github.com/usekaneo/kaneo/blob/main/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-key` header) 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`](https://github.com/usekaneo/kaneo/blob/main/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`](https://github.com/usekaneo/kaneo/blob/main/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`](https://github.com/usekaneo/kaneo/blob/main/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`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/auth.ts) and include rate-limiting protection. The OAuth Device Authorization flow in [`apps/api/src/mcp/oauth.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/mcp/oauth.ts) also enables CLI authentication through user-verified device codes.