Security Considerations for Kaneo: Authentication Architecture and Access Controls
Kaneo implements a defense-in-depth security model using Better Auth with mandatory 32-character secrets, adaptive cookie policies, rate limiting, and PostgreSQL advisory locks to prevent race conditions during admin promotion.
Kaneo is an open-source project management platform that leverages Better Auth to provide a comprehensive authentication layer. Understanding the security considerations for Kaneo is essential for administrators deploying self-hosted instances or managing cloud deployments, as the platform handles sensitive operations including workspace invitations, API key generation, and multi-provider OAuth authentication.
Authentication Architecture and Core Configuration
The foundation of Kaneo's security model resides in apps/api/src/auth.ts, which configures the Better Auth framework with multiple authentication plugins and security hooks. The architecture supports diverse authentication methods while maintaining strict validation rules for cryptographic materials.
Kaneo's authentication stack includes Email and Password authentication with bcrypt hashing, Magic Link passwordless login, One-Time Password (OTP) verification, and Social OAuth providers including GitHub, Google, and Discord. Additionally, the platform implements Device Authorization flows for CLI tools, API Key authentication for service accounts, and Bearer token support for programmatic access.
The system validates critical security parameters at startup. The AUTH_SECRET environment variable must contain at least 32 characters; otherwise, the application aborts initialization to prevent weak JWT signatures.
Cryptographic Secrets and Environment Variables
Kaneo relies on several environment-scoped secrets that require careful management during deployment. In apps/api/src/auth.ts, the application enforces strict validation rules and loads sensitive credentials from the environment.
The primary cryptographic secret, AUTH_SECRET, requires a minimum length of 32 characters to ensure sufficient entropy for JWT signing operations. For OAuth integrations, client secrets such as GITHUB_CLIENT_SECRET, GOOGLE_CLIENT_SECRET, and Discord credentials are loaded from environment variables without fallback values.
Cloudflare Turnstile integration depends on TURNSTILE_SECRET_KEY for CAPTCHA verification during email sign-up. Notably, self-hosted instances without this key fall back to an "OK" response, effectively bypassing CAPTCHA protection—a configuration intended for private deployments but requiring attention for public-facing instances.
Rate Limiting and Anti-Abuse Measures
Kaneo implements tiered rate limiting to prevent brute-force attacks and API abuse. The configuration in apps/api/src/auth.ts establishes global rate limiting parameters including window duration and maximum request thresholds.
In cloud deployments, custom rate limiting rules apply specifically to high-risk endpoints. The /sign-up/email endpoint and /organization/invite-member paths enforce stricter limits to prevent automated account creation and unauthorized workspace invitations. These rules operate alongside the disposable email blocking system to reduce phishing and spam vectors.
Cross-Origin Resource Sharing and Cookie Security
The platform dynamically constructs trustedOrigins from the KANEO_CLIENT_URL and API base URL to prevent unauthorized cross-origin requests. This CORS policy ensures that authentication cookies and tokens are only transmitted to legitimate front-end applications.
Cookie security policies adapt to deployment contexts. The sameSite attribute switches between none for cross-subdomain HTTPS deployments and lax for standard configurations, while the secure flag mirrors this decision to ensure cookies transmit only over encrypted connections. Administrators can optionally override the cookie domain using the COOKIE_DOMAIN environment variable to support complex hosting topologies.
CAPTCHA and Disposable Email Protection
Kaneo integrates Cloudflare Turnstile to verify human users during the email sign-up process. The verification logic in apps/api/src/utils/verify-turnstile.ts validates tokens against Cloudflare's API, rejecting requests that fail verification unless the secret key is absent.
For cloud deployments, Kaneo blocks disposable email addresses during registration and workspace invitations. The isDisposableEmail check prevents users from registering with throwaway domains, reducing the risk of spam accounts and improving audit trail reliability.
Guest Access Controls and Anonymous User Restrictions
Anonymous authentication introduces specific security considerations that Kaneo addresses through environment flags and permission checks. When DISABLE_GUEST_ACCESS is unset, the system permits anonymous account creation, which allows users to create workspaces without verified identities.
The platform enforces business logic restrictions on anonymous accounts. Guest users cannot send workspace invitations or promote themselves to admin roles, preventing privilege escalation from unauthenticated sessions. These checks appear in the request hooks defined in the authentication configuration.
Database Integrity and Race Condition Prevention
Kaneo's database schema in apps/api/src/database/schema.ts implements CUID2 identifiers for all primary keys, timestamp tracking for audit purposes, and cascading foreign key rules to maintain referential integrity. The apiKey plugin stores keys with nullable user_id references to align with Better Auth expectations while maintaining relational constraints.
To prevent race conditions during initial setup, Kaneo uses PostgreSQL advisory locks when promoting the first user to admin status. The pg_advisory_xact_lock serializes this critical operation in apps/api/src/auth.ts, ensuring that concurrent sign-up requests cannot result in multiple admin users or privilege conflicts.
MCP and Device Flow Security
For CLI and MCP (Kaneo Control Plane) integrations, the platform implements specialized authentication flows in packages/mcp/src/auth/auth-service.ts and packages/mcp/src/auth/device-flow.ts. These modules handle token storage and device authorization with client-ID validation to ensure only registered CLI applications can initiate device flows.
The device authorization flow validates client identifiers against an approved set before issuing tokens, preventing unauthorized applications from capturing user credentials through the device code flow.
Code Examples
The following examples demonstrate Kaneo's security implementations.
Verifying Turnstile tokens during sign-up:
import { verifyTurnstile } from "@/utils/verify-turnstile";
const token = ctx.body?.turnstileToken;
const ip = ctx.headers.get("cf-connecting-ip");
const result = await verifyTurnstile(token, ip);
if (!result.ok) throw new APIError("FORBIDDEN", { message: result.reason });
Validating device flow clients:
import { getDeviceAuthClientIds } from "@/auth";
deviceAuthorization({
verificationUri: getDeviceAuthVerificationUri(),
validateClient: async (clientId) => getDeviceAuthClientIds().has(clientId),
})
Enforcing restrictions on invitation endpoints:
if (ctx.path === "/organization/invite-member" && isCloud()) {
const session = await getSessionFromCtx(ctx, { disableRefresh: true });
if (session?.user?.isAnonymous) {
throw new APIError("FORBIDDEN", { message: "Guest accounts may not send workspace invitations." });
}
}
Summary
- Cryptographic validation: Kaneo requires 32-character
AUTH_SECRETvalues and validates OAuth credentials at startup to prevent weak signature algorithms. - Multi-layered authentication: Better Auth plugins provide email/password, OAuth, OTP, magic links, API keys, and device flows with bcrypt hashing and secure token generation.
- Adaptive security controls: Cookie policies automatically adjust
sameSiteandsecureflags based on deployment topology, while CORS restrictions derive from configured origins. - Anti-abuse mechanisms: Cloud deployments enforce CAPTCHA verification, disposable email blocking, and custom rate limits on sensitive endpoints like sign-up and invitations.
- Data integrity: CUID2 identifiers, PostgreSQL advisory locks for admin promotion, and foreign key cascades prevent race conditions and maintain relational consistency.
- Guest access limitations: Anonymous users face explicit restrictions on workspace invitations and admin promotion, controlled via
DISABLE_GUEST_ACCESSenvironment variables.
Frequently Asked Questions
What happens if the AUTH_SECRET is shorter than 32 characters?
Kaneo aborts the startup process and throws a validation error. According to the source code in apps/api/src/auth.ts, the application enforces this minimum length to ensure sufficient entropy for JWT signing, preventing token forgery attacks that could compromise user sessions.
Can I disable CAPTCHA verification in self-hosted Kaneo deployments?
Yes, self-hosted instances automatically bypass Turnstile verification when TURNSTILE_SECRET_KEY is not configured. However, for public-facing deployments, you should set this environment variable to enable Cloudflare Turnstile protection against automated sign-up abuse.
How does Kaneo prevent multiple users from becoming admins during initial setup?
The platform uses a PostgreSQL advisory lock (pg_advisory_xact_lock) during the first-user promotion process. This serializes the admin creation transaction in apps/api/src/auth.ts, ensuring that even with concurrent sign-up requests, only one user receives admin privileges.
Are API keys stored securely in the database?
API keys follow Better Auth's storage conventions with reference_id fields linking to user accounts. While the schema in apps/api/src/database/schema.ts maintains referential integrity, administrators must ensure x-api-key headers transmit over HTTPS and store key values securely in environment variables or secret managers rather than code repositories.
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 →