@ivalt/agent-auth 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -77
- package/assets/logo.svg +4 -0
- package/package.json +12 -2
package/README.md
CHANGED
|
@@ -1,70 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
push to the approver's phone, the human approves with biometrics (FaceID /
|
|
5
|
-
fingerprint, plus optional location / time / device checks), and the agent
|
|
6
|
-
receives a **PKI-signed attestation**.
|
|
3
|
+
<img src="https://unpkg.com/@ivalt/agent-auth/assets/logo.svg" alt="iVALT" width="80" height="80" />
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
# @ivalt/agent-auth
|
|
9
6
|
|
|
10
|
-
-
|
|
11
|
-
- **HTTP** (Streamable-HTTP) — a hostable endpoint (Docker image) for the
|
|
12
|
-
multi-tenant / remote use case.
|
|
7
|
+
**Human-in-the-loop authentication for AI agents**
|
|
13
8
|
|
|
14
|
-
|
|
15
|
-
client decides *when* to call and owns governance; iVALT owns the verify action.
|
|
9
|
+
Biometric approval with PKI-signed attestation — via [Model Context Protocol (MCP)](https://modelcontextprotocol.io).
|
|
16
10
|
|
|
17
|
-
|
|
11
|
+
[](https://www.npmjs.com/package/@ivalt/agent-auth)
|
|
12
|
+
[](https://www.npmjs.com/package/@ivalt/agent-auth)
|
|
13
|
+
[](https://www.npmjs.com/package/@ivalt/agent-auth)
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
|------|----------|
|
|
21
|
-
| `request_approval` | Blocking. Sends the request and waits up to `timeout_s` (default 90, max 120) for approval. Returns the attestation. |
|
|
22
|
-
| `request_approval_async` | Returns a `request_id` immediately. For long-running cloud agents. |
|
|
23
|
-
| `check_status` | Polls a `request_id` -> `pending` / `approved` (with attestation) / `denied` / `expired`. |
|
|
15
|
+
[Website](https://www.ivalt.com) · [Report issue](https://github.com/ivalt/agent-auth/issues)
|
|
24
16
|
|
|
25
|
-
|
|
26
|
-
the default — this is how one endpoint serves many tenants), `factors`
|
|
27
|
-
(`biometric` | `location` | `time` | `device`).
|
|
17
|
+
</div>
|
|
28
18
|
|
|
29
|
-
|
|
19
|
+
When an agent hits a sensitive step, this MCP server pauses the workflow, sends an iVALT push to the approver's phone, and returns a **PKI-signed attestation** after biometric approval (FaceID / fingerprint, plus optional location, time, and device checks).
|
|
30
20
|
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
"status": "approved",
|
|
34
|
-
"attestation": {
|
|
35
|
-
"approved": true,
|
|
36
|
-
"request_id": "a518d10b-...",
|
|
37
|
-
"approver": { "mobile": "+1...", "name": "Jane Doe", "email": "jane@example.com" },
|
|
38
|
-
"approver_mobile": "+1...",
|
|
39
|
-
"request_from": "iVALT MCP: <action>",
|
|
40
|
-
"factors_verified": { "biometric": true, "location": true, "time": false, "device": true },
|
|
41
|
-
"location": { "latitude": "32.84...", "longitude": "-79.86...", "address": "..." },
|
|
42
|
-
"signed_at": "2026-06-26T...Z",
|
|
43
|
-
"pki": { "public_key": "MIICIjANBgkq...", "signature": null, "key_ref": "a518d10b-..." },
|
|
44
|
-
"raw": { }
|
|
45
|
-
}
|
|
46
|
-
}
|
|
21
|
+
```
|
|
22
|
+
Agent step → request_approval → iVALT push → human approves → PKI attestation → agent continues
|
|
47
23
|
```
|
|
48
24
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
## Configuration
|
|
52
|
-
|
|
53
|
-
All config is via environment variables (see [`.env.example`](.env.example)).
|
|
54
|
-
With **no key set**, the server uses iVALT's public `ondemandid.com` proxy (no
|
|
55
|
-
credentials needed). Set `IVALT_API_KEY` to call `api.ivalt.com` directly.
|
|
25
|
+
## Install
|
|
56
26
|
|
|
57
|
-
|
|
58
|
-
|-----|---------|---------|
|
|
59
|
-
| `IVALT_API_KEY` / `IVALT_CONNECTION_ID` | _(none)_ | iVALT credential; presence switches upstream to `direct`. |
|
|
60
|
-
| `IVALT_UPSTREAM` | auto | Force `direct` or `proxy`. |
|
|
61
|
-
| `IVALT_DEFAULT_MOBILE` | _(none)_ | Default approver phone (E.164). If unset, callers must pass `approver_mobile` per request. |
|
|
62
|
-
| `IVALT_REQUEST_FROM` | `iVALT MCP` | Label on the approval request. |
|
|
63
|
-
| `IVALT_DEFAULT_FACTORS` | _(none)_ | Comma list of default factors. |
|
|
64
|
-
| `PORT` | `8080` | HTTP transport port. |
|
|
65
|
-
| `MCP_AUTH_TOKEN` | _(none)_ | Bearer token required on `POST /mcp`. |
|
|
27
|
+
No clone or build — run directly from npm:
|
|
66
28
|
|
|
67
|
-
|
|
29
|
+
```bash
|
|
30
|
+
npx -y @ivalt/agent-auth
|
|
31
|
+
```
|
|
68
32
|
|
|
69
33
|
### Cursor (`.cursor/mcp.json`)
|
|
70
34
|
|
|
@@ -83,20 +47,6 @@ credentials needed). Set `IVALT_API_KEY` to call `api.ivalt.com` directly.
|
|
|
83
47
|
}
|
|
84
48
|
```
|
|
85
49
|
|
|
86
|
-
Pre-publish, point at the local path instead:
|
|
87
|
-
|
|
88
|
-
```json
|
|
89
|
-
{
|
|
90
|
-
"mcpServers": {
|
|
91
|
-
"ivalt": {
|
|
92
|
-
"command": "node",
|
|
93
|
-
"args": ["C:/dev/iv/projects/mcp/bin/ivalt-mcp.js"],
|
|
94
|
-
"env": { "IVALT_DEFAULT_MOBILE": "+1..." }
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
50
|
### Claude Desktop
|
|
101
51
|
|
|
102
52
|
Same shape under `mcpServers` in `claude_desktop_config.json`.
|
|
@@ -115,10 +65,70 @@ client = MultiServerMCPClient({
|
|
|
115
65
|
}
|
|
116
66
|
})
|
|
117
67
|
tools = await client.get_tools() # request_approval, request_approval_async, check_status
|
|
118
|
-
# bind `tools` into your graph; use request_approval as a human-in-the-loop gate.
|
|
119
68
|
```
|
|
120
69
|
|
|
121
|
-
|
|
70
|
+
## Requirements
|
|
71
|
+
|
|
72
|
+
- **Node.js** 18+
|
|
73
|
+
- **iVALT credential** (optional) — without `IVALT_API_KEY`, the server uses iVALT's public demo proxy (`ondemandid.com`); set a key to call `api.ivalt.com` directly
|
|
74
|
+
- **Approver phone** — set `IVALT_DEFAULT_MOBILE` (E.164) or pass `approver_mobile` on each tool call
|
|
75
|
+
|
|
76
|
+
## Transports
|
|
77
|
+
|
|
78
|
+
- **stdio** — launched locally via `npx` (Cursor, Claude Desktop, LangGraph)
|
|
79
|
+
- **HTTP** (Streamable-HTTP) — hostable endpoint for multi-tenant / remote use (Docker)
|
|
80
|
+
|
|
81
|
+
The agent never sees the iVALT key — it lives only in this server's env.
|
|
82
|
+
|
|
83
|
+
## Tools
|
|
84
|
+
|
|
85
|
+
| Tool | Behavior |
|
|
86
|
+
|------|----------|
|
|
87
|
+
| `request_approval` | Blocking. Sends the request and waits up to `timeout_s` (default 90, max 120) for approval. Returns the attestation. |
|
|
88
|
+
| `request_approval_async` | Returns a `request_id` immediately. For long-running cloud agents. |
|
|
89
|
+
| `check_status` | Polls a `request_id` → `pending` / `approved` (with attestation) / `denied` / `expired`. |
|
|
90
|
+
|
|
91
|
+
Shared inputs: `action` (required), `reason`, `approver_mobile` (E.164, overrides the default — this is how one endpoint serves many tenants), `factors` (`biometric` \| `location` \| `time` \| `device`).
|
|
92
|
+
|
|
93
|
+
Approved responses return a normalized attestation:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"status": "approved",
|
|
98
|
+
"attestation": {
|
|
99
|
+
"approved": true,
|
|
100
|
+
"request_id": "a518d10b-...",
|
|
101
|
+
"approver": { "mobile": "+1...", "name": "Jane Doe", "email": "jane@example.com" },
|
|
102
|
+
"approver_mobile": "+1...",
|
|
103
|
+
"request_from": "iVALT MCP: <action>",
|
|
104
|
+
"factors_verified": { "biometric": true, "location": true, "time": false, "device": true },
|
|
105
|
+
"location": { "latitude": "32.84...", "longitude": "-79.86...", "address": "..." },
|
|
106
|
+
"signed_at": "2026-06-26T...Z",
|
|
107
|
+
"pki": { "public_key": "MIICIjANBgkq...", "signature": null, "key_ref": "a518d10b-..." },
|
|
108
|
+
"raw": { }
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Notes on the live shape: iVALT returns the device's registered public key in `raw.imei` (mapped to `pki.public_key`), the iVALT request UUID in `raw.request_id`, and geo data when the device shares it. This endpoint does not return a separate detached `signature`, so `pki.signature` is typically `null` while `pki.public_key` carries the PKI material. The complete upstream payload is always preserved under `raw`.
|
|
114
|
+
|
|
115
|
+
## Configuration
|
|
116
|
+
|
|
117
|
+
All config is via environment variables (see [`.env.example`](.env.example)).
|
|
118
|
+
|
|
119
|
+
| Var | Default | Purpose |
|
|
120
|
+
|-----|---------|---------|
|
|
121
|
+
| `IVALT_API_KEY` / `IVALT_CONNECTION_ID` | _(none)_ | iVALT credential; presence switches upstream to `direct`. |
|
|
122
|
+
| `IVALT_UPSTREAM` | auto | Force `direct` or `proxy`. |
|
|
123
|
+
| `IVALT_DEFAULT_MOBILE` | _(none)_ | Default approver phone (E.164). If unset, callers must pass `approver_mobile` per request. |
|
|
124
|
+
| `IVALT_REQUEST_FROM` | `iVALT MCP` | Label on the approval request. |
|
|
125
|
+
| `IVALT_DEFAULT_FACTORS` | _(none)_ | Comma list of default factors. |
|
|
126
|
+
| `PORT` | `8080` | HTTP transport port. |
|
|
127
|
+
| `MCP_AUTH_TOKEN` | _(none)_ | Bearer token required on `POST /mcp`. |
|
|
128
|
+
|
|
129
|
+
## Hosted HTTP transport
|
|
130
|
+
|
|
131
|
+
To connect to a hosted server instead of running locally (no Node needed on the client):
|
|
122
132
|
|
|
123
133
|
```python
|
|
124
134
|
client = MultiServerMCPClient({
|
|
@@ -130,9 +140,11 @@ client = MultiServerMCPClient({
|
|
|
130
140
|
})
|
|
131
141
|
```
|
|
132
142
|
|
|
133
|
-
##
|
|
143
|
+
## Development
|
|
134
144
|
|
|
135
145
|
```bash
|
|
146
|
+
git clone https://github.com/ivalt/agent-auth.git
|
|
147
|
+
cd agent-auth
|
|
136
148
|
npm install
|
|
137
149
|
|
|
138
150
|
# stdio (what Cursor/Claude/LangGraph spawn)
|
|
@@ -143,7 +155,7 @@ MCP_AUTH_TOKEN=secret PORT=8080 npm run start:http
|
|
|
143
155
|
curl http://localhost:8080/health
|
|
144
156
|
```
|
|
145
157
|
|
|
146
|
-
Quick wiring check
|
|
158
|
+
Quick wiring check:
|
|
147
159
|
|
|
148
160
|
```bash
|
|
149
161
|
node test/smoke.js stdio
|
|
@@ -151,7 +163,7 @@ node test/smoke.js http http://localhost:8080/mcp secret
|
|
|
151
163
|
# add SMOKE_FIRE=1 to also fire a real push to IVALT_DEFAULT_MOBILE
|
|
152
164
|
```
|
|
153
165
|
|
|
154
|
-
|
|
166
|
+
### Docker (HTTP transport)
|
|
155
167
|
|
|
156
168
|
```bash
|
|
157
169
|
docker build -t ivalt-mcp .
|
|
@@ -163,12 +175,14 @@ docker run -p 8080:8080 \
|
|
|
163
175
|
curl http://localhost:8080/health
|
|
164
176
|
```
|
|
165
177
|
|
|
166
|
-
The multi-tenant router connects to `POST /mcp` with the bearer token and passes
|
|
167
|
-
a per-tenant `approver_mobile` in each tool call.
|
|
178
|
+
The multi-tenant router connects to `POST /mcp` with the bearer token and passes a per-tenant `approver_mobile` in each tool call.
|
|
168
179
|
|
|
169
180
|
## Notes
|
|
170
181
|
|
|
171
|
-
- `request_id` encodes the approver mobile + issue time; iVALT's result endpoint
|
|
172
|
-
keys on the mobile, so avoid concurrent in-flight requests for the same phone.
|
|
182
|
+
- `request_id` encodes the approver mobile + issue time; iVALT's result endpoint keys on the mobile, so avoid concurrent in-flight requests for the same phone.
|
|
173
183
|
- Approval window is ~60s; blocking `request_approval` polls every 2s.
|
|
174
184
|
- HTTP runs in stateless mode (`GET`/`DELETE /mcp` return 405).
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
[MIT](LICENSE)
|
package/assets/logo.svg
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" role="img" aria-label="iVALT">
|
|
2
|
+
<rect width="120" height="120" rx="24" fill="#0E7C95"/>
|
|
3
|
+
<path fill="#fff" d="M36 78V42h12.4l11.2 28.4L70.8 42H83v36H73.6V58.8L63.2 78h-6.4L46.4 58.8V78H36zm44.8 0V42H91v36H80.8z"/>
|
|
4
|
+
</svg>
|
package/package.json
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ivalt/agent-auth",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Human-in-the-loop MCP server for AI agents — biometric approval with PKI-signed attestation. stdio + HTTP.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"author": "iVALT <info@ivalt.com> (https://www.ivalt.com)",
|
|
8
|
+
"homepage": "https://www.ivalt.com",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/ivalt/agent-auth.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/ivalt/agent-auth/issues"
|
|
15
|
+
},
|
|
7
16
|
"publishConfig": {
|
|
8
17
|
"access": "public"
|
|
9
18
|
},
|
|
@@ -21,6 +30,7 @@
|
|
|
21
30
|
},
|
|
22
31
|
"main": "src/server.js",
|
|
23
32
|
"files": [
|
|
33
|
+
"assets",
|
|
24
34
|
"bin",
|
|
25
35
|
"src",
|
|
26
36
|
".env.example",
|