How to Integrate Kaneo with Other Tools: A Complete Technical Guide

Kaneo integrates with external tools through a modular architecture that uses REST API endpoints, shared database schemas, WebSocket broadcasts, and reusable React hooks to connect services like Slack, GitHub, Gitea, Discord, and custom webhooks.

Kaneo is designed as an extensible, open-source project management platform. This guide breaks down exactly how its integration system works under the hood, drawing directly from the usekaneo/kaneo source code.

Kaneo Integration Architecture Overview

All Kaneo integrations follow a consistent six-layer architecture. Understanding these layers shows how to integrate Kaneo with other tools using established patterns.

1. Backend API Endpoints

Each integration lives under a dedicated /api/{integration}-integration namespace. These routes are built with Hono and validated by Valibot.

In apps/api/src/slack-integration/index.ts, the route definition looks like this:

import { Hono } from 'hono';
import { createSlackIntegration, deleteSlackIntegration, getSlackIntegration } from './controllers';

export const slackIntegration = new Hono()
  .get('/', getSlackIntegration)
  .post('/', createSlackIntegration)
  .delete('/', deleteSlackIntegration);

This pattern repeats across GitHub (/api/github-integration), Gitea (/api/gitea-integration), Discord (/api/discord-integration), and webhook integrations.

2. Database Schema for Integrations

Integration data is stored in a shared integration table defined in apps/api/src/database/schema.ts. The schema includes:

  • type — discriminator for the integration service (slack, github, gitea, etc.)
  • projectId — association to the Kaneo project
  • config — provider-specific JSON configuration
  • OAuth tokens and refresh credentials

This unified approach lets Kaneo query all integrations for a project with a single database call.

3. Real-Time WebSocket Broadcasts

When integrations change, connected clients receive updates immediately. The broadcast system in apps/api/src/ws/broadcast-adapter.ts supports both single-instance and multi-instance deployments:

// apps/api/src/ws/broadcast-adapter.ts
export async function broadcastIntegrationChange(projectId: string, payload: any) {
  await broadcastAdapter.publish(`project:${projectId}:integration`, JSON.stringify(payload));
}
  • Development: In-memory adapter
  • Production: Redis-backed adapter for horizontal scaling

4. Frontend Fetchers and React Query Hooks

Each integration exposes typed fetcher functions and corresponding hooks. For example, Slack integration uses:

These hooks automatically:

  • Cache server state with React Query
  • Invalidate related queries on mutation
  • Surface errors via toast notifications

5. OAuth and Device Flow Authentication

For providers requiring OAuth (GitHub, Gitea, Discord) or device authorization, Kaneo uses a reusable auth-service.ts located at packages/mcp/src/auth/auth-service.ts. This service handles:

  • Token exchange and storage
  • Automatic token refresh
  • Secure credential encryption

The device flow implementation at packages/mcp/src/auth/device-flow.ts follows RFC 8628 for headless authentication scenarios.

6. RBAC Permission Enforcement

All integration routes enforce the same role-based access control as core Kaneo features. The middleware in apps/api/src/auth.ts validates that the requesting user has appropriate permissions (viewer, member, or admin) before allowing integration operations.

Practical Integration Examples

Connecting Slack to a Kaneo Project

Here's a complete React component that demonstrates how to integrate Kaneo with Slack using the provided hooks:

import { useCreateSlackIntegration } from '@/hooks/mutations/slack-integration/use-slack-integration';
import { useGetSlackIntegration } from '@/hooks/queries/slack-integration/use-get-slack-integration';

function SlackConnect({ projectId }: { projectId: string }) {
  const { data: slack, isLoading } = useGetSlackIntegration(projectId);
  const createMutation = useCreateSlackIntegration(projectId);

  if (isLoading) return <p>Loading integration status...</p>;
  if (slack?.connected) return <p>✓ Slack is connected to this project.</p>;

  return (
    <button
      onClick={() => createMutation.mutate({ webhookUrl: 'https://hooks.slack.com/services/...' })}
      disabled={createMutation.isLoading}
    >
      {createMutation.isLoading ? 'Connecting...' : 'Connect Slack'}
    </button>
  );
}

The useCreateSlackIntegration hook handles POSTing to /api/slack-integration with proper error handling and cache invalidation.

Implementing GitHub OAuth Server-Side

For GitHub integration, the OAuth callback controller in apps/api/src/github-integration/controllers/oauth-callback.ts exchanges temporary codes for access tokens:

import { Hono } from 'hono';
import { getGithubToken } from '@/mcp/auth/token-store';
import { upsertGithubIntegration } from '@/github-integration/service';

export const githubOAuthCallback = new Hono()
  .get('/', async (c) => {
    const code = c.req.query('code');
    const state = c.req.query('state'); // Contains projectId for association
    
    const token = await getGithubToken(code);
    await upsertGithubIntegration({ 
      userId: c.get('userId'), 
      projectId: state,
      token 
    });
    
    return c.redirect('/dashboard/settings/integrations');
  });

Adding a Custom Integration to Kaneo

To integrate a new external tool with Kaneo, follow this implementation roadmap:

  1. Extend the database schema — Add provider-specific fields to apps/api/src/database/schema.ts

  2. Create API routes — Implement Hono routes in apps/api/src/{service}-integration/index.ts with Valibot validation

  3. Build controller logic — Handle authentication, webhook verification, and business logic in apps/api/src/{service}-integration/controllers/

  4. Expose frontend fetchers — Add typed HTTP wrappers in apps/web/src/fetchers/{service}-integration/

  5. Create React Query hooks — Implement data fetching hooks in apps/web/src/hooks/queries/{service}-integration/

  6. Build UI components — Add settings panels and connection buttons in apps/web/src/components/integrations/

  7. Update permissions — Register any new required scopes in apps/api/src/auth.ts

  8. Write comprehensive tests — Cover API endpoints in tests/api/** and full flows in tests/api-integration/**

Key Source Files for Kaneo Integrations

Component Path Purpose
API route definitions apps/api/src/slack-integration/index.ts REST endpoint registration
Integration schema apps/api/src/database/schema.ts Unified database structure
WebSocket broadcasting apps/api/src/ws/broadcast-adapter.ts Real-time client updates
OAuth service packages/mcp/src/auth/auth-service.ts Token management and refresh
Device flow packages/mcp/src/auth/device-flow.ts RFC 8628 implementation
Frontend fetchers apps/web/src/fetchers/*-integration/* HTTP client abstractions
React Query hooks apps/web/src/hooks/queries/*-integration/ Data synchronization
Integration UI apps/web/src/components/integrations/ Settings and connection UI
Permission middleware apps/api/src/auth.ts RBAC enforcement
Test suites tests/api/**, tests/api-integration/** Verification coverage

Summary

  • Kaneo uses a standardized pattern for all integrations: Hono API routes → controllers → database → WebSocket broadcast → React Query hooks
  • Existing integrations (Slack, GitHub, Gitea, Discord, webhooks) demonstrate production-ready implementations you can reference
  • The integration table in apps/api/src/database/schema.ts serves as the central store for all connected services
  • Real-time synchronization happens through apps/api/src/ws/broadcast-adapter.ts, supporting both single and multi-instance deployments
  • Adding new tools requires consistent changes across eight layers: database, API, controllers, fetchers, hooks, UI, permissions, and tests

Frequently Asked Questions

What authentication methods does Kaneo support for integrations?

Kaneo supports three primary authentication patterns according to the source code: standard OAuth 2.0 for GitHub, Gitea, and Discord; OAuth Device Flow (RFC 8628) for headless or CLI scenarios via packages/mcp/src/auth/device-flow.ts; and simple webhook URL validation for services like Slack. The reusable auth-service.ts handles token storage, encryption, and automatic refresh across all OAuth providers.

How does Kaneo keep integration data synchronized across clients?

Kaneo broadcasts integration changes through WebSocket messages using the adapter pattern in apps/api/src/ws/broadcast-adapter.ts. When any integration is created, updated, or deleted, the server publishes to a project-scoped channel (project:${projectId}:integration), and connected clients receive the payload instantly. The production configuration uses Redis as the broadcast backend to support multiple API instances.

Can I integrate Kaneo with tools that aren't officially supported?

Yes. The modular architecture in usekaneo/kaneo is designed for extension. You need to implement the eight-step pattern: database schema extension, Hono API routes, controller logic, frontend fetchers, React Query hooks, UI components, permission updates, and tests. Reference the existing slack-integration or github-integration directories as working templates.

Where are integration credentials stored securely?

OAuth tokens and sensitive configuration are stored in the integration table's encrypted config column, defined in apps/api/src/database/schema.ts. The packages/mcp/src/auth/auth-service.ts module handles encryption at rest and provides methods for secure token retrieval. Environment-specific encryption keys should be configured via the application's secure configuration system.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →