Skip to content

Conversation

@victor-inkeep
Copy link

@victor-inkeep victor-inkeep commented Jan 27, 2026

Slack integration for Inkeep Agents with workspace installation, user account linking via Nango, and slash command support. I added a modular "Work Apps" architecture for future integrations.

API Authentication Pattern: Session Token Flow

How are authenticated API calls are made from Slack commands? We are using the user's session token:

Flow Overview

  1. User links Slack account via Nango OAuth flow
  2. Session token is captured from useAuthSession() and stored in Nango connection metadata
  3. Slash commands retrieve token from connection metadata and use it for API calls

Implementation
Frontend captures session token during linking (slack-provider.tsx):

const { session } = useAuthSession();const { sessionToken } = await slackApi.createConnectSession({  userId: user.id,  sessionToken: session?.token,  // Pass current session token  sessionExpiresAt: session?.expiresAt,});
Backend stores token in Nango metadata (slack.ts):
app.post('/connect', async (c) => {  const { userId, sessionToken, sessionExpiresAt } = body;    // Store for retrieval after Nango OAuth completes  pendingSessionTokens.set(userId, { token: sessionToken, ... });});

API client uses Bearer token for requests (api-client.ts):

export class SlackApiClient {  private get headers(): Record<string, string> {    return {      'Content-Type': 'application/json',      Authorization: `Bearer ${this.sessionToken}`,    };  }  async listProjects(): Promise<PaginatedResponse<Project>> {    return this.request('GET', `/manage/tenants/${this.tenantId}/projects`);  }}

Commands use the client (commands/index.ts):

const client = createSlackApiClient(connection);  // Gets token from connectionconst result = await client.listProjects();

Features

  • Workspace Installation: OAuth flow to install Slack app to workspaces
  • User Account Linking: Connect Slack users to Inkeep accounts via Nango
  • Slash Commands: /inkeep link|status|list|logout|help (subject to change)
  • Work Apps UI: New modular architecture at /work-apps with Slack management dashboard
  • State Management: TanStack Query for server state, Zustand for client state
  • Local DB Preview: Mock localStorage database for development (prep for PostgreSQL)

Test Plan
[ ] Install Slack app to workspace via OAuth
[ ] Link user account through Nango flow
[ ] Verify /inkeep list returns projects using session token auth
[ ] Test session refresh on reconnection
[ ] Verify disconnect clears connection properly

image

Add initial landing page at /[tenantId]/slack-app with account info,
connection status, and install button placeholder.
    - Add /manage/slack/install and /oauth_redirect API routes
    - Add Slack env vars (CLIENT_ID, CLIENT_SECRET, SIGNING_SECRET, APP_URL)
    - Update .env.example files with Slack configuration template
    - Update slack-app page with Install to Slack button
    - Display installed workspaces with bot token
    - Use localStorage for workspace data (DB integration coming soon)
    - Fix hydration mismatch with mounted state pattern
    - Add  Nango Connect UI to use production URLs (not local dev MCP URLs)
    - Add hasConnected flag to prevent false "cancelled" toast after successful nango connect
    - Enrich Nango connection metadata with Slack user info via API call
      (slack_username, slack_display_name, slack_email, is_slack_admin, is_slack_owner)
    - Add findConnectionBySlackUser helper to look up connections by Slack user ID
    - Add slack command  /inkeep status to show actual linked Inkeep account info
    - Add /inkeep link to link to dashboard and  show "Already Connected" if user is linked
    - Add /inkeep disconnect to delete Nango connection directly from Slack
    - Add /manage/slack/events endpoint for Slack URL verification
    - Add Slack-specific Nango env vars (NANGO_SLACK_SECRET_KEY, NANGO_SLACK_INTEGRATION_ID)
Backend:
- Add @slack/web-api, @slack/bolt, slack-block-builder packages
- Create modular service structure under services/slack/:
  - types.ts, client.ts, nango.ts, security.ts
  - blocks/index.ts with slack-block-builder message templates
  - commands/index.ts with handler functions
- Refactor slack routes to use new services
- Add GET /status and POST /disconnect API endpoints
- Add findConnectionByAppUser and getConnectionStatus helpers
- Store tenantId in Nango metadata for proper API context
- Add SLACK_BOT_TOKEN to env schema

Frontend:
- Add TanStack Query layer (api/slack-api.ts, api/queries.ts)
- Create PostgreSQL-like localStorage schema:
  - WorkspaceRecord, UserRecord, SlackUserConnection, AuditLogRecord
  - Full CRUD operations in db/local-db.ts
- Add useWorkspaceDb, useSlackSync hooks
- Update DatabasePreviewCard with 5 tabs:
  Workspaces, Users, Slack, Audit, Raw JSON
- Save workspace installs and user connections to new database
- Add workspace installation check before allowing user linking
- Fix disconnect flow to call Nango API and clear local state
- Add clickable workspace links in Installed Workspaces table
- Add new /work-apps route with overview page showing all work apps
- Move Slack dashboard to /work-apps/slack sub-route
- Update sidebar: rename 'Slack App' to 'Work Apps', use Plug icon
- Add stub work apps: GitHub, Discord, Linear, Notion, Jira (Coming Soon)
- Create WorkAppCard component with status badges and actions
- Add custom SVG icons for work app integrations
- Add auto-refresh for Database Preview on connection changes:
  - Dispatch 'inkeep-db-update' custom event on data changes
  - Listen for event in useDatabaseState hook
- Add back navigation link from Slack dashboard to Work Apps
- Remove Session column from Database Preview (not stored)
- Remove updateSessionToken function (not needed)
…sues

    - Store session token in Nango metadata for authenticated Slack API calls
    - Add /refresh-session endpoint to update token on re-login
    - Fix infinite fetch loop causing Slack rate limiting
    - Fix OAuth redirect to new /work-apps/slack route
    - Replace custom hooks with TanStack Query + Zustand store
    - Fix hydration mismatches with proper mounted state pattern
    - Use Bearer token auth for Slack commands instead of cookie
    - Add SlackApiClient for modular, DRY API calls
    - Add session refresh on dashboard visit to keep Nango token fresh
    - Sync localDb on connect/disconnect for database preview
    - Add auto-dismiss (5s) and manual close button to notification banner
    - Handle 404 gracefully in workspace info query (no error toast on disconnect)
    - Add workspace count indicator and Beta badge to Work Apps UI
    - Remove external link from card (available in Installed Workspaces instead)
    - Extract localDb sync helpers to db/sync.ts for future PostgreSQL migration
    - Add SlackNotificationAction type for type-safe notification triggers
@changeset-bot
Copy link

changeset-bot bot commented Jan 27, 2026

⚠️ No Changeset found

Latest commit: 5e61b1d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Jan 27, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
agents-api Ready Ready Preview, Comment Jan 28, 2026 8:18pm
agents-manage-ui Ready Ready Preview, Comment Jan 28, 2026 8:18pm
1 Skipped Deployment
Project Deployment Review Updated (UTC)
agents-docs Skipped Skipped Jan 28, 2026 8:18pm

Request Review

@victor-inkeep victor-inkeep self-assigned this Jan 27, 2026
@claude
Copy link

claude bot commented Jan 27, 2026

Claude finished @victor-inkeep's task —— View job


Staff Engineer Code Review - Slack Integration v2

Conducting comprehensive architectural and code quality review for the Slack integration feature.

Review Tasks:

  • Analyze overall architecture and Work Apps modular design
  • Review session token authentication flow and security considerations
  • Evaluate database schema and state management patterns
  • Review API routes and client implementation
  • Assess UI components and user experience
  • Check error handling and edge cases
  • Evaluate scalability and extensibility
  • Review testing coverage and patterns

Review Summary

This PR introduces a comprehensive Slack integration with a modular "Work Apps" architecture. While the implementation is functionally sound, there are several critical security concerns and architectural considerations that need to be addressed.

🚨 Critical Security Issues

1. Session Token Storage in Third-Party Service (HIGH)

Location: agents-api/src/domains/manage/routes/slack.ts:362-367, agents-manage-ui/src/features/slack/context/slack-provider.tsx:186-194

The current implementation stores Inkeep session tokens in Nango connection metadata, which introduces significant security risks:

// Storing sensitive session tokens in external service
inkeep_session_token: pendingSession.token,
inkeep_session_expires_at: pendingSession.expiresAt,

Issues:

  • Session tokens are stored in a third-party service (Nango)
  • No guarantee of encryption at rest in Nango
  • Creates unnecessary dependency on external service for security-critical data
  • Potential for token exposure through Nango's admin interfaces or logs

Recommendation:

  • Store session tokens in your own database with proper encryption
  • Use connection ID as a foreign key to link to your internal session store
  • Implement token refresh mechanism that doesn't rely on external storage

2. In-Memory Session Storage Without Persistence (MEDIUM)

Location: agents-api/src/domains/manage/routes/slack.ts:42-55

const pendingSessionTokens = new Map<string, { token: string; expiresAt: string; createdAt: number }>();

Issues:

  • Memory-based storage will lose all pending sessions on service restart
  • No persistence layer for session state during OAuth flow
  • Could lead to failed user connections during deployments

Recommendation:

  • Move to Redis or database-backed session storage
  • Implement proper cleanup and expiration policies

3. Insufficient Request Validation (MEDIUM)

Location: agents-api/src/domains/manage/routes/slack.ts:392-397

if (env.SLACK_SIGNING_SECRET) {
  if (!verifySlackRequest(env.SLACK_SIGNING_SECRET, body, timestamp, signature)) {
    // ... error handling
  }
}

Issues:

  • Request verification is conditional on environment variable presence
  • No validation when signing secret is missing
  • Commands could be executed without proper authentication in misconfigured environments

Recommendation:

  • Make request verification mandatory for all Slack endpoints
  • Fail fast if signing secret is not configured
  • Add comprehensive logging for security events

🏗️ Architectural Concerns

4. Local Database Implementation is Over-Engineered (MEDIUM)

Location: agents-manage-ui/src/features/slack/db/local-db.ts

The local database implementation (574+ lines) creates unnecessary complexity:

Issues:

  • Complex localStorage abstraction when simple state management would suffice
  • Audit logging in frontend (unnecessary for local development data)
  • Sophisticated querying capabilities not needed for development mocking
  • Creates maintenance burden with minimal benefit

Recommendation:

  • Simplify to basic Zustand store for development
  • Remove audit logging from frontend
  • Use server state management (TanStack Query) for real data

5. Work Apps Architecture Needs Extension Points (LOW)

Location: agents-manage-ui/src/features/work-apps/types.ts:19-81

Current implementation hardcodes all future integrations:

export const WORK_APPS_CONFIG: Record<WorkAppId, Omit<WorkApp, 'status' | 'installUrl' | 'dashboardUrl'>> = {
  slack: { /* config */ },
  github: { /* config */ },
  discord: { /* config */ },
  // ... all future apps hardcoded
};

Recommendation:

  • Create plugin-based architecture for work apps
  • Allow dynamic registration of integrations
  • Separate core framework from specific integrations

✅ Positive Aspects

Strong Error Handling

The Slack API client includes comprehensive error handling with specific error types and user-friendly messages.

Modular Architecture Foundation

The Work Apps concept provides a good foundation for future integrations, though it needs refinement for extensibility.

Comprehensive State Management

Good use of TanStack Query for server state and Zustand for client state, following React best practices.

🧪 Testing Gaps

Critical Missing: No tests found for any Slack integration code. For a feature of this complexity and security sensitivity, comprehensive testing is essential:

Required Tests:

  • Unit tests for authentication flows
  • Integration tests for Slack OAuth callback handling
  • Security tests for request verification
  • API client error handling tests
  • UI component tests

📋 Required Actions Before Merge

High Priority (Must Fix)

  1. Move session token storage to internal database with proper encryption
  2. Make Slack request verification mandatory - remove conditional behavior
  3. Add comprehensive test coverage for all Slack functionality
  4. Implement persistent session storage (Redis/database) instead of in-memory Map

Medium Priority (Should Fix)

  1. Simplify local database implementation - reduce complexity for development tooling
  2. Add proper error boundaries in React components for better UX
  3. Implement session refresh mechanism that doesn't depend on external storage

Low Priority (Consider)

  1. Refactor Work Apps for extensibility - move toward plugin architecture
  2. Add security event logging for audit trails
  3. Consider rate limiting for Slack webhook endpoints

🎯 Verdict

This PR introduces valuable functionality but has critical security issues that must be resolved before merging. The session token storage pattern is particularly concerning and could expose user authentication data.

The architectural foundation is solid, but the implementation needs security hardening and testing before production deployment.


@victor-inkeep victor-inkeep added the enhancement New feature or request label Jan 27, 2026
Extract Slack integration into a modular work-apps domain for better
separation of concerns and future extractability. This sets up a clean
boundary for third-party integrations that can be easily exported.

Changes:
    - Create new work-apps domain at agents-api/src/domains/work-apps/
    - Move Slack routes from /manage/slack/* to /work-apps/slack/*
    - Update OAuth redirect URIs to use /work-apps/slack/oauth_redirect
    - Update frontend slack-api.ts to call /work-apps/slack/* endpoints
    - Export workAppsRoutes from domains barrel file

API endpoints are now:
    - /work-apps/slack/install
    - /work-apps/slack/connect
    - /work-apps/slack/commands
    - /work-apps/slack/status
    - etc.
…default agent

@mention improvements:
- Add real-time streaming responses using Slack's chatStream API
- Support thread context inference - mentioning bot in thread without
  query uses thread history as context
- Fix authentication by using API key pattern instead of session token
- Filter out data-operation metadata events from streamed responses
- Filter bot messages to prevent event loops
- Add session token validation with user-friendly reconnect prompts

Default agent persistence:
- Persist workspace default agent in Nango metadata (survives restarts)
- Fall back to in-memory cache for performance
- Add getWorkspaceDefaultAgentFromNango and setWorkspaceDefaultAgent

Slash commands:
- Add /inkeep run [agent] [question] command
- Add /inkeep settings for personal default agent
- Add /inkeep list to show available agents
- Add /inkeep help with comprehensive command reference

Other:
- Add legacy route mount at /manage/slack for backwards compatibility
- Export DefaultAgentConfig type from nango services
… types

Update tsconfig.json exclude to be more specific, excluding .next/cache,
.next/server, and .next/static instead of the entire .next directory.
This allows .next/types/routes.d.ts to be processed, providing global
PageProps, LayoutProps, and RouteContext types.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants