NIN Connect Docs
Platform (Self-Host)

Platform Architecture

Internal code structure — the execution proxy, credential vault, OAuth engine, API key auth, and Firebase auth.

System Overview

NIN Connect is a Next.js 15 monorepo with three layers:

  1. Dashboard — admin and developer UI for managing plugins, tools, auth methods, categories, submissions, reviews, API keys, connections, and logs
  2. Runtime API — SDK-facing REST endpoints that list plugins/tools, manage user connections, and execute tools with auth injection (only serves approved plugins)
  3. SDK — TypeScript client (@nin.in/core) that wraps the runtime API

Internal Architecture

┌─────────────────────────────────────────────────┐
│                   Dashboard                      │
│   (Admin: plugins, review queue, categories)     │
│   (Developer: submissions, my plugins, API keys) │
│   (Shared: connections, logs)                    │
└──────────────────────┬──────────────────────────┘
                       │ CRUD via /api/dashboard/*

┌─────────────────────────────────────────────────┐
│              PostgreSQL (Drizzle ORM)             │
│  plugins │ tools │ auth_methods │ categories     │
│  connected_accounts │ api_keys │ execution_logs  │
└──────────────────────┬──────────────────────────┘

        ┌──────────────┼──────────────┐
        ▼              ▼              ▼
  /api/v1/plugins  /api/v1/tools  /api/v1/connections
        │              │
        │         /api/v1/tools/execute
        │              │
        │              ▼
        │    ┌──────────────────┐
        │    │  Execution Proxy  │
        │    │  ─ resolve tool   │
        │    │  ─ decrypt creds  │
        │    │  ─ inject auth    │
        │    │  ─ call ext. API  │
        │    │  ─ log result     │
        │    └──────────────────┘


  ┌──────────────┐     ┌───────────────────┐
  │  @nin.in/core   │────▶│  Developer's App   │
  │  (SDK)       │     │  / AI Agent        │
  └──────────────┘     └───────────────────┘

Key Components

Execution Proxy (lib/proxy/executor.ts)

The core of the runtime. When a tool is executed:

  1. Resolves the tool by slug from the database
  2. Looks up the plugin's base URL
  3. Finds the end-user's connected account and auth method
  4. Decrypts stored credentials (AES-256-GCM)
  5. Injects auth into request headers based on auth method type (OAuth2 bearer, API key header, custom injection rules, etc.)
  6. Interpolates path parameters and builds the request body
  7. Calls the external API
  8. Logs the execution result (success/error, latency)

If an OAuth2 token is expired, the proxy auto-refreshes it before making the call.

Credential Vault (lib/encryption/)

All user credentials are encrypted at rest using AES-256-GCM with a 32-byte key from the ENCRYPTION_KEY environment variable. Credentials are only decrypted at the moment of tool execution — never exposed to the dashboard, SDK, or logs.

OAuth Engine (lib/oauth/)

Handles the full OAuth 2.0 Authorization Code flow:

  • initiateOAuth2 — builds the authorization URL with signed state token
  • exchangeCode — exchanges authorization code for tokens at the token endpoint
  • refreshAccessToken — refreshes expired access tokens using the refresh token
  • State tokens — HMAC-signed, base64url-encoded payloads that carry developerId, userId, pluginId, authMethodId, and redirectUrl

API Key Auth (lib/api-key/)

Developer API keys follow a secure pattern:

  • Keys are prefixed nk_live_ followed by 24 random bytes (base64url)
  • Only the SHA-256 hash is stored in the database
  • The raw key is shown once at creation time
  • The withApiKey middleware validates keys on all /api/v1/* routes

Firebase Auth

Dashboard users authenticate via Firebase (Google sign-in). The POST /api/auth/sync endpoint verifies Firebase tokens and upserts developer records. Admin routes use requireAdmin(), developer routes use authenticateDeveloper(), and plugin-scoped routes use requirePluginAccess() for creator-or-admin authorization.

Submission & Approval Flow

All new plugins — whether created by a developer or an admin — follow a unified lifecycle:

Draft → Pending Review → Approved (Live)
                       → Declined / Revision Requested → Edit → Resubmit

Only approved plugins are exposed through the public Runtime API (/api/v1/*). The execution proxy also enforces the reviewStatus = "approved" check, preventing tool execution against unapproved plugins.

Project Structure

apps/web/src/
├── app/
│   ├── (auth)/login/          # Google sign-in page
│   ├── (dashboard)/           # Admin + developer dashboard pages (plugins, submissions, reviews)
│   ├── connect/               # Hosted connect pages for end-users
│   └── api/
│       ├── auth/              # Firebase token sync
│       ├── dashboard/         # Admin/developer CRUD endpoints
│       ├── connect/           # Public connect page APIs
│       └── v1/               # SDK-facing runtime API
├── components/
│   ├── plugin-builder/        # Plugin/tool form components
│   └── ui/                    # Shadcn UI components
└── lib/
    ├── api-key/               # Key generation, validation, withApiKey middleware
    ├── auth/                  # Firebase auth context + requireAdmin + requirePluginAccess
    ├── db/                    # Drizzle client, schema, migrations, seed
    ├── encryption/            # AES-256-GCM encrypt/decrypt
    ├── oauth/                 # OAuth2 engine + state tokens
    ├── proxy/                 # Tool execution proxy
    └── utils.ts               # Tailwind cn() helper

Tech Stack

LayerTechnology
FrameworkNext.js 15 (App Router, Turbopack)
UITailwind CSS v3, Shadcn/Radix UI
DatabasePostgreSQL (Neon) via Drizzle ORM
AuthFirebase Auth (Google sign-in)
EncryptionAES-256-GCM (Node.js crypto)
ValidationZod
SDKTypeScript (@nin.in/core)
Monorepopnpm workspaces + Turborepo

On this page