How Kaneo Handles Authentication: A Complete Technical Guide
Kaneo uses Better Auth as its authentication foundation, combining JWT tokens, session cookies, API keys, and OAuth providers to secure both its API and React-based web interface.
Kaneo is an open-source project management platform built by usekaneo. Understanding how Kaneo handles authentication is essential for contributors, self-hosters, and security auditors. This article breaks down the complete authentication architecture based on the actual source code implementation.
Core Authentication Components
Kaneo's authentication stack relies on five primary mechanisms working together:
| Component | Purpose | Implementation |
|---|---|---|
| JWT tokens | Stateless session proof | Signed with AUTH_SECRET (minimum 32 characters) from .env |
| Session cookies | Persistent browser sessions | HTTP-only, SameSite=Lax cookies managed by Better Auth |
| API keys | Programmatic access | Validated by authenticate-api-request.ts via Authorization: Bearer <key> header |
| OAuth providers | SSO login | GitHub, Google, Discord, and custom OIDC through environment variables |
| Turnstile (CAPTCHA) | Bot protection | Verified by verify-turnstile.ts on sign-up and sensitive actions |
Authentication Request Flow
Understanding the sequence of authentication checks helps debug issues and extend the system:
-
Request enters the API through
apps/api/src/auth.tswhere Better Auth middleware extracts the JWT cookie or Bearer token. -
Better Auth validates the token and injects context—
c.get("user")andc.get("userId")become available to downstream handlers. -
API-key validation occurs in parallel for programmatic requests via
authenticate-api-request.ts, which may enforce additional scopes. -
Authorization checks apply fine-grained permissions through utilities like
authorize-asset-access.tsandrequire-workspace-permission.ts. -
Frontend synchronization happens through
auth-client.ts, which supplies session tokens to TanStack Query hooks and handles automatic refresh.
Key Implementation Files
These source files define Kaneo's authentication behavior:
| File Path | Responsibility |
|---|---|
apps/api/src/auth.ts |
Central Better Auth configuration and middleware registration |
apps/api/src/utils/authenticate-api-request.ts |
API key validation logic |
apps/api/src/utils/authorize-asset-access.ts |
Asset permission enforcement |
apps/web/src/lib/auth-client.ts |
React client wrapper for Better Auth |
apps/web/src/routes/auth.tsx |
UI routes for login, registration, and SSO |
apps/api/src/utils/verify-turnstile.ts |
CAPTCHA verification utility |
Code Examples: Authentication in Practice
Protecting an API Route
The Better Auth middleware automatically populates the Hono context with user information:
// apps/api/src/some-feature/controllers/example.ts
import { Hono } from "hono";
export const example = new Hono()
.get(
"/protected",
async (c) => {
const userId = c.get("userId");
if (!userId) {
return c.json({ error: "Unauthenticated" }, 401);
}
// Business logic executes only for authenticated users
return c.json({ message: `Hello user ${userId}` });
},
);
Configuring the Frontend Auth Client
The shared client ensures consistent authentication behavior across the React application:
// apps/web/src/lib/auth-client.ts
import { createAuthClient } from "@better-auth/react";
import { VITE_API_URL } from "@/config";
export const authClient = createAuthClient({
apiUrl: VITE_API_URL,
// Automatic token refresh is handled internally
});
Protecting a React Component
Conditional rendering based on authentication state:
// apps/web/src/routes/dashboard.tsx
import { useAuth } from "@/lib/auth-client";
export default function Dashboard() {
const { user, loading } = useAuth();
if (loading) return <Spinner />;
if (!user) return <Redirect to="/login" />;
return <div>Welcome, {user.email}!</div>;
}
Security Mechanisms
Kaneo implements multiple defense layers to protect authentication data:
- HTTP-only cookies prevent JavaScript access to session tokens, mitigating XSS attacks
- SameSite=Lax cookie policy restricts cross-origin request contexts
- JWT signatures guarantee token integrity without database lookups
- Hashed API keys stored in the database support revocation at any time
- Turnstile integration blocks automated account creation attempts
- Role-based access control enforced through workspace membership checks
Environment Configuration
Authentication behavior is controlled through environment variables:
# Required: Minimum 32-character secret for JWT signing
AUTH_SECRET=your-super-secret-32-char-minimum-key
# OAuth provider credentials (optional)
GITHUB_CLIENT_ID=xxx
GITHUB_CLIENT_SECRET=xxx
GOOGLE_CLIENT_ID=xxx
GOOGLE_CLIENT_SECRET=xxx
# Turnstile for bot protection
TURNSTILE_SECRET_KEY=xxx
Summary
- Better Auth provides the foundational authentication library for Kaneo's entire stack
- Dual token system separates browser sessions (JWT cookies) from API access (Bearer keys)
- Middleware-based validation in
apps/api/src/auth.tsinjects user context into all API routes - Fine-grained authorization utilities enforce workspace and asset-level permissions
- React integration through
auth-client.tsprovides automatic session management - Security-hardened defaults include HTTP-only cookies, JWT signing, and CAPTCHA protection
Frequently Asked Questions
What authentication library does Kaneo use?
Kaneo uses Better Auth, a flexible TypeScript authentication library that supports multiple login methods including credentials, OAuth providers, and API keys. The integration is configured in apps/api/src/auth.ts and consumed by the React frontend through @better-auth/react.
How does Kaneo validate API requests from external services?
External services authenticate using API keys passed in the Authorization: Bearer <key> header. The apps/api/src/utils/authenticate-api-request.ts utility validates these keys against hashed database records and can enforce additional permission scopes beyond standard user sessions.
Where are authentication routes defined in the Kaneo codebase?
All user-facing authentication UI—login, registration, password reset, and OAuth callbacks—lives in apps/web/src/routes/auth.tsx. These routes use the shared auth-client.ts to communicate with the Better Auth backend, ensuring consistent behavior between server and client authentication state.
How does Kaneo prevent automated account creation?
Kaneo integrates Cloudflare Turnstile for invisible CAPTCHA protection. The apps/api/src/utils/verify-turnstile.ts utility validates Turnstile tokens on registration and other sensitive actions, blocking bots without degrading legitimate user experience.
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 →