Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ jobs:
VERSION=${{ steps.version.outputs.VERSION }}
cat > homebrew-tap/Formula/amesh.rb << FORMULA
class Amesh < Formula
desc "Hardware-bound M2M authentication CLI — replaces static API keys with device identities"
desc "Device-bound M2M authentication CLI — replaces static API keys with device identities"
homepage "https://github.com/ameshdev/amesh"
version "${VERSION}"
license "MIT"
Expand Down
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ app.use(amesh.verify());

## How It Works

- **Device identity** --- each machine gets a unique P-256 ECDSA keypair. The private key is protected by the OS keychain (macOS) or TPM 2.0 (Linux) and never leaves the device.
- **Device identity** --- each machine gets a unique P-256 ECDSA keypair. The private key is protected by the OS keychain (macOS), TPM 2.0 (Linux), or an encrypted file (cloud VMs) and never leaves the device.
- **One-way trust** --- controllers authenticate to targets, never the reverse. A compromised server cannot call back to your laptop.
- **Signed requests** --- every HTTP request is signed with the device's private key. The signature covers method, path, timestamp, nonce, and body.
- **Replay protection** --- each request has a unique nonce and a 30-second timestamp window. Nonces are tracked server-side.
Expand All @@ -108,7 +108,7 @@ app.use(amesh.verify());
| [`@authmesh/sdk`](./packages/sdk) | Signing fetch client + Express verification middleware |
| [`@authmesh/cli`](./packages/cli) | CLI: `init`, `listen`, `invite`, `list`, `revoke`, `provision` |
| [`@authmesh/core`](./packages/core) | Crypto primitives: sign, verify, canonical string, nonce, HMAC, HKDF, ECDH |
| [`@authmesh/keystore`](./packages/keystore) | Key storage drivers: Secure Enclave, macOS Keychain, TPM 2.0 |
| [`@authmesh/keystore`](./packages/keystore) | Key storage drivers: Secure Enclave, macOS Keychain, TPM 2.0, encrypted file |
| [`@authmesh/relay`](./packages/relay) | WebSocket relay for device pairing handshakes |

---
Expand Down Expand Up @@ -154,6 +154,10 @@ See the [Self-Hosting Guide](./docs/self-hosting.md) for deployment options.

---

## Language Support

amesh currently provides a **TypeScript/Node.js SDK**. The protocol is language-agnostic (standard HTTP headers + ECDSA-P256 signatures), so verification can be implemented in any language. SDKs for Python and Go are planned.

## Using amesh with AI Assistants

amesh is designed to be easy to integrate with AI coding assistants like Claude, Copilot, and Cursor. The packages have full TypeScript types, and the API surface is minimal.
Expand All @@ -173,7 +177,7 @@ The SDK has two main functions: `amesh.fetch()` (client) and `amesh.verify()` (s
```bash
bun install # install all deps
bun run build # turbo build (tsc -b per package)
bun run test # 135 tests across all packages
bun run test # tests across all packages
bun run lint # eslint + prettier
```

Expand Down
2 changes: 1 addition & 1 deletion docs/architecture-decisions.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Key decisions made during spec review and project bootstrap (March 2026). Each e
| 2 | macOS Keychain | Swift helper → software keychain (unsigned binary fallback) |
| 3 | Linux TPM 2.0 | `tpm2-tools` subprocess via `execFile` (not `exec`) |

Note: The encrypted-file fallback (Tier 4) was removed in v0.1.3. amesh now requires hardware-backed key storage.
Note: The encrypted-file fallback (Tier 3) is available as an explicit opt-in (`--backend encrypted-file --passphrase`) for cloud VMs and containers without hardware key storage. Hardware backends are always preferred when available.

---

Expand Down
10 changes: 8 additions & 2 deletions docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ What you can do with amesh, step by step.
```bash
bun install
bun run build
bun run test # 135 tests across 5 packages
bun run test # tests across all packages
bun run lint # eslint + prettier check
```

Expand All @@ -33,7 +33,11 @@ Identity created.
Backend : keychain
```

amesh requires hardware-backed key storage (Secure Enclave, macOS Keychain, or TPM 2.0). If no hardware backend is detected, `init` will fail.
amesh uses hardware-backed key storage when available (Secure Enclave, macOS Keychain, or TPM 2.0). On machines without hardware key storage (cloud VMs, containers), use the encrypted-file backend:

```bash
amesh init --name "prod-api" --backend encrypted-file --passphrase "$AUTH_MESH_PASSPHRASE"
```

This creates two files:
- `~/.amesh/identity.json` — your device ID, public key, friendly name
Expand Down Expand Up @@ -181,6 +185,8 @@ import { amesh } from '@authmesh/sdk';

const app = express();
app.use(express.json());

// Works with express.json(), express.text(), or no body parser at all.
app.use(amesh.verify());

app.post('/api/orders', (req, res) => {
Expand Down
22 changes: 14 additions & 8 deletions docs/integration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,10 @@ import express from 'express';
import { amesh } from '@authmesh/sdk';

const app = express();

// Parse body as text so amesh can verify the signature over the raw body
app.use(express.text({ type: '*/*' }));
app.use(express.json());

// Add amesh verification middleware — checks signature, timestamp, nonce, allow list
// Works with express.json(), express.text(), or no body parser at all.
app.use('/api', amesh.verify());

// Public endpoint (no auth)
Expand Down Expand Up @@ -174,7 +173,7 @@ import express from 'express';
import { amesh } from '@authmesh/sdk';

const app = express();
app.use(express.text({ type: '*/*' }));
app.use(express.json());
app.use(amesh.verify());

app.get('/internal/users/:id', (req, res) => {
Expand Down Expand Up @@ -230,7 +229,7 @@ import { amesh } from '@authmesh/sdk';
import { RedisNonceStore } from '@authmesh/sdk/redis';

const app = express();
app.use(express.text({ type: '*/*' }));
app.use(express.json());

app.use(amesh.verify({
nonceStore: new RedisNonceStore(process.env.REDIS_URL),
Expand Down Expand Up @@ -324,7 +323,7 @@ interface VerifyOptions {

1. **Devices not paired?** Run `amesh list` on the server — the client's device ID must be in the allow list.
2. **Clock skew?** Server and client clocks must be within 30 seconds. Check with `date` on both machines.
3. **Body mismatch?** The middleware must parse the body as text (`express.text({ type: '*/*' })`), not as JSON. If you use `express.json()`, the re-serialized body may differ from what the client signed.
3. **Body mismatch?** The middleware handles `express.json()`, `express.text()`, and raw streams automatically. If you use a custom body parser that transforms the body (e.g., XML parsing, decompression), ensure the original body is preserved.

### "allow_list_integrity_failure" (500)

Expand All @@ -334,6 +333,13 @@ The allow list file (`~/.amesh/allow_list.json`) was modified outside of amesh.

You're running in production without a Redis nonce store. Replay attacks could succeed by hitting different instances. See Recipe 3 above.

### "amesh requires hardware-backed key storage"
### "No supported key storage backend detected"

amesh prefers hardware-backed storage (Secure Enclave, macOS Keychain, TPM 2.0) but also supports an encrypted-file backend for cloud VMs:

```bash
amesh init --name "my-server" --backend encrypted-file --passphrase "your-passphrase"
# Or set AUTH_MESH_PASSPHRASE environment variable
```

amesh requires Secure Enclave (macOS), macOS Keychain, or TPM 2.0 (Linux). If no hardware backend is detected, `amesh init` will fail. Ensure you're running on a machine with supported hardware. On macOS, the Swift helper binary (`amesh-se-helper`) must be installed alongside the `amesh` binary.
On macOS, ensure the Swift helper binary (`amesh-se-helper`) is installed alongside the `amesh` binary for Keychain/Secure Enclave support.
Loading
Loading