@credninja/server
v1.0.0
Published
Self-hosted credential delegation server for AI agents. Uses @credninja/oauth + @credninja/vault
Maintainers
Readme
@credninja/server
Self-hosted credential delegation server for AI agents.
Stores OAuth tokens in an encrypted vault and serves delegated access tokens to authenticated agents. Run on a separate host from your AI agents for true credential isolation.
Quick Start
# Install
npm install @credninja/server
# Set up configuration
cp node_modules/@credninja/server/.env.example .env
# Edit .env — set VAULT_PASSPHRASE, AGENT_TOKEN, and at least one provider
# Run
npx cred-serverOr from the repo:
cd packages/server
cp .env.example .env
# Edit .env
npm run devHow It Works
┌─────────────────┐ ┌──────────────────────┐ ┌─────────────┐
│ AI Agent │ HTTP │ Cred Server │ OAuth │ Google │
│ (Machine B) │────────▸│ (Machine A) │────────▸│ GitHub │
│ │◂────────│ │◂────────│ Slack ... │
│ Bearer token │ token │ Encrypted vault │ tokens │ │
└─────────────────┘ └──────────────────────┘ └─────────────┘- Admin connects providers — Visit
/connect/googlein a browser, complete OAuth - Tokens stored encrypted — AES-256-GCM, PBKDF2-SHA256 key derivation
- Agent requests token —
GET /api/token/googlewith Bearer auth - Server returns access token — Auto-refreshes if expired. Refresh token never leaves the server.
Endpoints
| Method | Path | Auth | Description |
|--------|------|------|-------------|
| GET | /health | None | Liveness check |
| GET | /providers | None | List configured providers + connection status |
| GET | /connect/:provider | None | Start OAuth flow (browser) |
| GET | /connect/:provider/callback | None | OAuth callback |
| GET | /api/token/:provider | Bearer | Get delegated access token |
| DELETE | /api/token/:provider | Bearer | Revoke stored credentials |
Configuration
All configuration via environment variables (or .env file):
| Variable | Required | Description |
|----------|----------|-------------|
| VAULT_PASSPHRASE | Yes | Encryption passphrase for the token vault |
| AGENT_TOKEN | Yes | Bearer token for agent API access (must start with cred_at_) |
| PORT | No | Server port (default: 3456) |
| HOST | No | Bind address (default: 127.0.0.1) |
| VAULT_STORAGE | No | file (default) or sqlite |
| VAULT_PATH | No | Path to vault file (default: ./data/vault.json) |
| REDIRECT_BASE_URI | No | OAuth redirect base (default: http://localhost:3456) |
| GOOGLE_CLIENT_ID | No | Google OAuth client ID |
| GOOGLE_CLIENT_SECRET | No | Google OAuth client secret |
| GITHUB_CLIENT_ID | No | GitHub OAuth client ID |
| GITHUB_CLIENT_SECRET | No | GitHub OAuth client secret |
| SLACK_CLIENT_ID | No | Slack OAuth client ID |
| SLACK_CLIENT_SECRET | No | Slack OAuth client secret |
| ... | No | Same pattern for NOTION, SALESFORCE, LINEAR, HUBSPOT |
Docker Deployment (Production)
cd packages/server
cp .env.example .env
# Edit .env with your credentials
# Build and run
docker compose up -d
# Verify
curl http://localhost:3456/healthThe vault is stored in a named Docker volume (cred-data) — survives container restarts and rebuilds.
HTTPS with Caddy
For production with automatic TLS:
- Point your domain's DNS to the server
- Edit
Caddyfile— replacecred.yourdomain.comwith your domain - Uncomment the
caddyservice indocker-compose.yml - Run
docker compose up -d
Caddy auto-provisions Let's Encrypt certificates. Agents connect via https://cred.yourdomain.com.
Updating
cd packages/server
git pull
docker compose build
docker compose up -dVault data is in the named volume and survives rebuilds.
Two-Machine Setup (Production)
For true credential isolation, run the server on a separate host from your agents:
1. Server (Machine A)
# On your server (VPS, on-prem, etc.)
git clone https://github.com/cred-ninja/sdk.git
cd sdk/packages/server
cp .env.example .env
# Edit .env with your credentials
# Install Caddy for automatic HTTPS
sudo apt install caddy
# Configure Caddy (create /etc/caddy/Caddyfile)
echo 'cred.yourdomain.com {
reverse_proxy localhost:3456
}' | sudo tee /etc/caddy/Caddyfile
sudo systemctl restart caddy
# Start the server
npm install && npm start2. Agent (Machine B)
import { Cred } from '@credninja/sdk';
const cred = new Cred({
agentToken: process.env.CRED_AGENT_TOKEN!,
baseUrl: 'https://cred.yourdomain.com',
});
const google = await cred.delegate({
service: 'google',
userId: 'default',
});
// Use google.accessToken with any Google APIOr with curl:
curl https://cred.yourdomain.com/api/token/google \
-H "Authorization: Bearer $CRED_AGENT_TOKEN"Security
- Refresh tokens never leave the server. The
/api/token/:providerendpoint returns only the access token. - Vault encrypted at rest with AES-256-GCM (PBKDF2-SHA256, 100K iterations).
- Agent tokens validated using constant-time comparison (timing-attack resistant).
- HTTPS required for remote access. The SDK refuses to send agent tokens over HTTP to non-localhost servers.
- For production: Always run behind a TLS reverse proxy (Caddy auto-provisions certificates).
Programmatic Usage
import { createServer, loadConfig } from '@credninja/server';
const config = loadConfig(); // reads from process.env
const { app, vault } = createServer(config);
await vault.init();
app.listen(3456);License
MIT
