{"id":39674647,"url":"https://github.com/clay-good/qiuth","last_synced_at":"2026-01-18T09:44:05.828Z","repository":{"id":325523638,"uuid":"1084616573","full_name":"clay-good/qiuth","owner":"clay-good","description":"Transform API keys from bearer tokens into proof-of-possession tokens, requiring multiple authentication factors to prevent unauthorized access even if your API key is leaked.","archived":false,"fork":false,"pushed_at":"2025-11-21T19:50:52.000Z","size":135,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-21T21:20:47.476Z","etag":null,"topics":["api","proof-of-possession","security"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/clay-good.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-27T23:29:16.000Z","updated_at":"2025-11-21T19:58:42.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/clay-good/qiuth","commit_stats":null,"previous_names":["clay-good/qiuth"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/clay-good/qiuth","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clay-good%2Fqiuth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clay-good%2Fqiuth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clay-good%2Fqiuth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clay-good%2Fqiuth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/clay-good","download_url":"https://codeload.github.com/clay-good/qiuth/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clay-good%2Fqiuth/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28534175,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T00:39:45.795Z","status":"online","status_checked_at":"2026-01-18T02:00:07.578Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","proof-of-possession","security"],"created_at":"2026-01-18T09:44:05.209Z","updated_at":"2026-01-18T09:44:05.812Z","avatar_url":"https://github.com/clay-good.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Qiuth\n\n**Multi-Factor Authentication for API Keys** - Stop treating API keys like passwords.\n\n\u003e **Qiuth** transforms API keys from bearer tokens into proof-of-possession tokens, requiring multiple authentication factors to prevent unauthorized access even if your API key is leaked.\n\nPronounced **chew-auth**. Inspired by [Kevin Qiu](https://www.linkedin.com/in/kevinmqiu)\n\n---\n\n## The Problem\n\n**API keys are single points of failure.** If your API key is leaked (committed to GitHub, intercepted in transit, stolen from logs), an attacker has **unlimited access** to your API.\n\n```bash\n# Your .env file accidentally committed to GitHub\nAPI_KEY=sk_live_abc123def456\n\n# Attacker finds it and has full access\ncurl -H \"Authorization: Bearer sk_live_abc123def456\" https://api.yourapp.com/data\n# SUCCESS - Attacker downloads all your data\n```\n\n**This happens more often than you think:**\n- Thousands of API keys leaked on GitHub every day\n- `.env` files accidentally committed to public repos\n- API keys logged in error messages or monitoring tools\n- Keys intercepted in transit or stolen from compromised systems\n- Even with key pairs, if the private key is leaked, it's game over\n\n---\n\n## The Solution\n\n**Qiuth adds multi-factor authentication to your API keys**, transforming them from bearer tokens (anyone with the key can use it) into **proof-of-possession tokens** (you need the key PLUS additional factors).\n\n### Multiple Layers of Defense\n\n1. **IP Allowlisting** - First line of defense\n   - Verify requests come from authorized locations\n   - Support for IPv4/IPv6 CIDR notation\n   - Blocks unauthorized networks immediately\n\n2. **TOTP MFA** - Time-based one-time passwords\n   - Works for service accounts (programmatic)\n   - Tokens change every 30 seconds\n   - Even if API key is leaked, attacker needs TOTP secret\n\n3. **Request Signing** - Cryptographic proof (choose one):\n\n   **Certificate Authentication** (asymmetric)\n   - Requires RSA private key to sign each request\n   - Only public key stored on server\n   - Best for external clients or when key distribution is a concern\n\n   **HMAC Authentication** (symmetric)\n   - Uses shared secret for request signing\n   - Simpler setup, same security for internal services\n   - Best for trusted environments and service-to-service communication\n\n4. **Timestamp Validation** - Prevents replay attacks\n   - Signed requests include timestamp\n   - Server rejects stale requests (configurable window)\n   - Even captured requests cannot be replayed\n\n### Real-World Impact\n\n**After Qiuth:**\n```bash\n# API key leaked in GitHub\nAPI_KEY=sk_live_abc123def456\n\n# Attacker tries to use it\ncurl -H \"X-API-Key: sk_live_abc123def456\" https://api.yourapp.com/data\n# FAILED: 401 Unauthorized - IP not in allowlist\n\n# Attacker would need ALL of these:\n# 1. API key (leaked)\n# 2. TOTP secret (stored separately)\n# 3. Signing key (private key OR HMAC secret)\n# = Virtually impossible to compromise\n```\n\n---\n\n## Why Qiuth?\n\n### The Non-Human Identity (NHI) Security Gap\n\nWe invest heavily in multi-factor authentication for human accounts. Password managers, authenticator apps, hardware keys - the security industry has made MFA standard for people.\n\n**But what about service accounts?**\n\nService accounts, API clients, and machine-to-machine integrations typically authenticate with:\n- Static API keys that never rotate\n- OAuth client_id/client_secret pairs with no second factor\n- Long-lived tokens with no additional verification\n\nThis creates a fundamental security gap: **non-human identities have weaker authentication than human identities**, despite often having broader access to sensitive systems.\n\n### The OAuth Client Secret Problem\n\nMany developers think \"just use OAuth\" solves API security. But OAuth client secrets have the same vulnerabilities as API keys:\n\n- **Client secrets are static** - They don't change unless manually rotated\n- **Client secrets are reusable** - Anyone with the secret can request tokens\n- **Client secrets can be intercepted** - MITM the initial token request and you have the secret\n- **Client secrets are essentially passwords** - With all the same risks of credential theft\n\nThe JP Morgan Chase CISO's [open letter to third-party suppliers](https://www.jpmorganchase.com/about/technology/blog/open-letter-to-our-suppliers) highlighted these exact concerns about OAuth and current authentication standards for machine-to-machine communication.\n\n### Why IP Allowlisting Should Be Standard\n\nA simple question: **Why is it so difficult for SaaS apps to add IP allowlisting?**\n\nConsider this real-world scenario: An engineer accidentally commits a config file containing a root access key to a public repository. Within minutes, automated scanners find it. The key is compromised.\n\nThis could have been a non-issue with a simple IAM policy:\n```\nDeny all access with this key if source IP is not in [VPN_STATIC_IP]\n```\n\nEven trivial IP validation - reading the X-Forwarded-For header before returning a response - would dramatically reduce the blast radius of leaked credentials. Yet most APIs don't offer this basic protection.\n\nQiuth makes IP allowlisting a first-class feature, not an afterthought.\n\n### Qiuth's Approach: MFA for ALL Identities\n\nQiuth applies the same security rigor to service accounts that we expect for human accounts:\n\n| Human Account | Service Account (with Qiuth) |\n|--------------|------------------------------|\n| Password | API Key |\n| IP-based access controls | IP Allowlisting (Layer 1) |\n| Authenticator app (TOTP) | TOTP for services (Layer 2) |\n| Hardware security key | Certificate signing (Layer 3) |\n\nThe result: even if your API key leaks, an attacker needs to also compromise your TOTP secret AND your private key AND make requests from an allowed IP address.\n\n**That's defense in depth for machine identities.**\n\n---\n\n## Quick Start\n\n### Installation\n\n```bash\nnpm install qiuth\n```\n\n### Basic Usage\n\n```typescript\nimport { QiuthConfigBuilder, QiuthAuthenticator, generateKeyPair } from 'qiuth';\n\n// Generate certificate key pair for maximum security\nconst { publicKey, privateKey } = generateKeyPair({ modulusLength: 2048 });\n\n// Configure all three security layers\nconst config = new QiuthConfigBuilder()\n  .withApiKey('your-api-key')\n  .withIpAllowlist(['192.168.1.0/24'])\n  .withTotp('your-totp-secret')\n  .withCertificate(publicKey) // Add certificate-based authentication\n  .build();\n\n// Authenticate requests\nconst authenticator = new QiuthAuthenticator();\nconst result = await authenticator.authenticate({\n  apiKey: 'user-provided-key',\n  clientIp: '192.168.1.100',\n  totpToken: '123456',\n  signature: 'base64-signature', // Required when using withCertificate\n  timestamp: Date.now().toString(),\n  method: 'GET',\n  url: 'https://api.example.com/resource',\n}, config);\n\nif (result.success) {\n  console.log('Authentication successful!');\n} else {\n  console.error('Authentication failed:', result.errors);\n}\n```\n\n**Note:** Use `.withCertificate(publicKey)` for maximum security. This requires clients to cryptographically sign each request with their private key, providing proof-of-possession that prevents unauthorized access even if API keys and TOTP secrets are compromised.\n\n### Framework Middleware\n\nQiuth provides middleware for popular Node.js frameworks:\n\n| Framework | Function | Runtime |\n|-----------|----------|---------|\n| Express | `createQiuthMiddleware` | Node.js |\n| Fastify | `qiuthFastifyPlugin` | Node.js |\n| Koa | `createQiuthKoaMiddleware` | Node.js |\n| Hono | `createQiuthHonoMiddleware` | Node.js, Cloudflare Workers, Deno, Bun |\n\n#### Express\n\n```typescript\nimport express from 'express';\nimport { createQiuthMiddleware, QiuthConfigBuilder } from 'qiuth';\n\nconst app = express();\n\nconst qiuthAuth = createQiuthMiddleware({\n  configLookup: async (apiKey) =\u003e {\n    return await db.getApiKeyConfig(apiKey);\n  },\n});\n\napp.get('/api/protected', qiuthAuth, (req, res) =\u003e {\n  res.json({ message: 'Access granted!' });\n});\n```\n\n#### Fastify\n\n```typescript\nimport fastify from 'fastify';\nimport { qiuthFastifyPlugin } from 'qiuth';\n\nconst app = fastify();\n\napp.register(qiuthFastifyPlugin, {\n  configLookup: async (apiKey) =\u003e await db.getApiKeyConfig(apiKey),\n});\n\napp.get('/protected', { preHandler: app.qiuthAuth }, async (request, reply) =\u003e {\n  return { authenticated: true };\n});\n```\n\n#### Koa\n\n```typescript\nimport Koa from 'koa';\nimport { createQiuthKoaMiddleware } from 'qiuth';\n\nconst app = new Koa();\n\nconst qiuthMiddleware = createQiuthKoaMiddleware({\n  configLookup: async (apiKey) =\u003e await db.getApiKeyConfig(apiKey),\n});\n\napp.use(qiuthMiddleware);\n```\n\n#### Hono (Edge-ready)\n\n```typescript\nimport { Hono } from 'hono';\nimport { createQiuthHonoMiddleware } from 'qiuth';\n\nconst app = new Hono();\n\napp.use('/api/*', createQiuthHonoMiddleware({\n  configLookup: async (apiKey) =\u003e await db.getApiKeyConfig(apiKey),\n}));\n```\n\n[Full Middleware Documentation](./docs/middleware-integrations.md)\n\n---\n\n## Interactive Demo\n\n**See Qiuth in action in 5 minutes!**\n\n```bash\n# Clone the repo\ngit clone https://github.com/clay-good/qiuth.git\ncd qiuth\n\n# Install dependencies\nnpm install\n\n# Start the interactive demo\nnpm run demo\n```\n\nThe demo server will start and display test credentials. Open a new terminal and try the test commands to see all three security layers in action!\n\n**What you'll experience:**\n- Level 1: Basic API key authentication\n- Level 2: API key + IP allowlisting\n- Level 3: API key + IP + TOTP MFA\n- Level 4: Full security (all three layers)\n- Failure scenarios (wrong credentials, expired tokens, invalid signatures)\n\n[**Full Demo Guide**](./demo/README.md)\n\n---\n\n## Features\n\n### Security\n- **Three-layer authentication** - IP, TOTP, and certificate-based\n- **Fail-fast validation** - Stop at first failure for performance\n- **Replay attack prevention** - Timestamp validation\n- **Secure credential generation** - Cryptographically secure random generation\n- **API key hashing** - SHA-256 for secure storage\n\n### Developer Experience\n- **TypeScript-first** - Full type definitions included\n- **Fluent API** - Intuitive configuration builder\n- **Express middleware** - Drop-in authentication\n- **HTTP client** - Automatic request signing\n- **CLI tool** - Generate credentials easily\n\n### Production Ready\n- **Zero-downtime credential rotation** - Transition periods for updates\n- **Structured logging** - Comprehensive observability\n- **Metrics collection** - Track authentication performance\n- **Environment configuration** - Load from env vars\n- **Comprehensive error handling** - Detailed error messages\n\n### Build \u0026 Distribution\n- **Dual module support** - ESM and CommonJS\n- **Tree-shakeable** - Import only what you need\n- **Zero dependencies** - Only Node.js built-ins\n- **Well-tested** - 318 tests with 90%+ coverage\n\n---\n\n## Use Cases\n\n### 1. Service-to-Service Authentication\nSecure microservices communication with MFA:\n```typescript\nconst config = new QiuthConfigBuilder()\n  .withApiKey(process.env.API_KEY)\n  .withIpAllowlist(['10.0.0.0/8']) // Internal network\n  .withTotp(process.env.TOTP_SECRET)\n  .build();\n```\n\n### 2. API Key Management\nAdd MFA to your existing API key system:\n```typescript\napp.use('/api', createQiuthMiddleware({ config }));\n```\n\n### 3. Compliance Requirements\nMeet PCI DSS, SOC 2, HIPAA security requirements:\n```typescript\nconst config = new QiuthConfigBuilder()\n  .withApiKey(apiKey)\n  .withIpAllowlist(allowedIps)\n  .withTotp(totpSecret)\n  .withCertificate(publicKey) // Maximum security\n  .build();\n```\n\n### 4. CI/CD Pipeline Security\nSecure automated deployments:\n```typescript\n// GitHub Actions, Jenkins, etc.\nconst client = new QiuthClient({\n  apiKey: process.env.API_KEY,\n  totpSecret: process.env.TOTP_SECRET,\n  privateKey: process.env.PRIVATE_KEY,\n});\n```\n\n---\n\n## Security\n\nQiuth is designed with security as the top priority:\n\n- **No sensitive data logging** - API keys and secrets never logged\n- **Cryptographically secure** - Uses Node.js crypto module\n- **RFC compliant** - TOTP follows RFC 6238\n- **Industry standards** - RSA-SHA256 signatures\n- **Regular audits** - Automated security scanning\n\n---\n\n## Performance\n\nQiuth is designed for production use with minimal overhead:\n\n- **IP Validation**: \u003c 1ms\n- **TOTP Validation**: \u003c 5ms\n- **Certificate Validation**: \u003c 10ms\n- **Total**: \u003c 20ms for all three layers\n\n**Bundle Size:**\n- ESM: ~60 KB\n- CommonJS: ~61 KB\n- TypeScript declarations: ~48 KB\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n**Stop treating API keys like passwords. Add multi-factor authentication today.**\n\n[Get Started](./docs/getting-started.md) • [Try the Demo](./demo/README.md) • [Readme](https://github.com/clay-good/qiuth/readme.md)\n\n\u003c/div\u003e\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclay-good%2Fqiuth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclay-good%2Fqiuth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclay-good%2Fqiuth/lists"}