@agentvisa/verify 0.1.0

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 ADDED
@@ -0,0 +1,178 @@
1
+ # @agentvisa/verify
2
+
3
+ Verify human-authorized AI agents in one call. Drop into any Node.js backend — Express, Fastify, Next.js, or plain `fetch`. Supports [Web Bot Auth (RFC 9421)](https://blog.cloudflare.com/web-bot-auth/) via the `AgentVisa-Assertion` header.
4
+
5
+ ```bash
6
+ npm install @agentvisa/verify
7
+ ```
8
+
9
+ ---
10
+
11
+ ## The two-layer model
12
+
13
+ Cloudflare's [Web Bot Auth](https://blog.cloudflare.com/web-bot-auth/) tells you **which company's agent** is making a request — operator identity, cryptographically signed. It stops there by design. AgentVisa adds the missing half:
14
+
15
+ ```
16
+ Layer 1 — Web Bot Auth (Cloudflare)
17
+ "This request is from Acme Corp's agent — verified."
18
+
19
+ Layer 2 — AgentVisa (this library)
20
+ "A real human (Face ID, just now) authorized that agent to act."
21
+ ```
22
+
23
+ When both are present, the `AgentVisa-Assertion` token is covered by the RFC 9421 signature — operator identity and human authorization cryptographically bound in one request.
24
+
25
+ ---
26
+
27
+ ## Quick start
28
+
29
+ Get your `widgetId` and `apiKey` from your [AgentVisa dashboard](https://agentvisa.ai/dashboard/vendor).
30
+
31
+ ### Express middleware
32
+
33
+ ```typescript
34
+ import express from 'express';
35
+ import { agentVisa } from '@agentvisa/verify';
36
+
37
+ const app = express();
38
+
39
+ // Reject any request without a valid AgentVisa token
40
+ app.use('/api', agentVisa({
41
+ widgetId: process.env.AGENTVISA_WIDGET_ID!,
42
+ apiKey: process.env.AGENTVISA_API_KEY!,
43
+ }));
44
+
45
+ app.post('/api/checkout', (req, res) => {
46
+ // req.agentVisa is populated — token is valid
47
+ res.json({ ok: true });
48
+ });
49
+ ```
50
+
51
+ ### Flag mode (decide in your handler)
52
+
53
+ ```typescript
54
+ app.use(agentVisa({
55
+ widgetId: process.env.AGENTVISA_WIDGET_ID!,
56
+ apiKey: process.env.AGENTVISA_API_KEY!,
57
+ onFail: 'flag', // don't auto-reject — let the handler decide
58
+ }));
59
+
60
+ app.post('/api/order', (req, res) => {
61
+ if (!req.agentVisa?.valid) {
62
+ // Downgrade: show a CAPTCHA, require extra confirmation, etc.
63
+ return res.status(401).json({ error: 'human_required' });
64
+ }
65
+ // Full trust path
66
+ res.json({ ok: true });
67
+ });
68
+ ```
69
+
70
+ ### Standalone (any framework)
71
+
72
+ ```typescript
73
+ import { extractToken, verify } from '@agentvisa/verify';
74
+
75
+ // Works with any framework — Next.js, Fastify, plain Node http, etc.
76
+ async function handler(req, res) {
77
+ const { token } = extractToken(req.headers);
78
+ if (!token) return res.status(401).json({ error: 'agentvisa_required' });
79
+
80
+ const result = await verify(token, {
81
+ widgetId: process.env.AGENTVISA_WIDGET_ID!,
82
+ apiKey: process.env.AGENTVISA_API_KEY!,
83
+ });
84
+
85
+ if (!result.valid) return res.status(401).json({ error: result.reason });
86
+ // Proceed
87
+ }
88
+ ```
89
+
90
+ ### Web Bot Auth (RFC 9421)
91
+
92
+ When an agent sends `AgentVisa-Assertion` instead of `X-AgentVisa-Token`, the library detects that the token was bound in a Web Bot Auth signature and reports it:
93
+
94
+ ```typescript
95
+ app.post('/api/action', (req, res) => {
96
+ const av = req.agentVisa!;
97
+
98
+ console.log(av.valid); // true — human verified
99
+ console.log(av.webBotAuthBound); // true — token covered by RFC 9421 signature
100
+ // false — arrived via X-AgentVisa-Token (standard)
101
+
102
+ // Both true = complete trust: which agent + which human, cryptographically bound
103
+ });
104
+ ```
105
+
106
+ > **Note:** `webBotAuthBound: true` confirms the structural binding is present. The RFC 9421 signature cryptography is verified by your WAF/CDN (e.g. Cloudflare Web Bot Auth) before the request reaches your app.
107
+
108
+ ---
109
+
110
+ ## API reference
111
+
112
+ ### `agentVisa(options)` — Express middleware
113
+
114
+ | Option | Type | Required | Description |
115
+ |--------|------|----------|-------------|
116
+ | `widgetId` | `string` | ✓ | Your `wgt_xxx` widget ID |
117
+ | `apiKey` | `string` | ✓ | Your `wk_xxx` API key |
118
+ | `onFail` | `'reject' \| 'flag'` | — | `'reject'` (default) sends 401; `'flag'` sets `req.agentVisa` and continues |
119
+ | `rejectBody` | `object` | — | Custom body for 401 responses |
120
+ | `apiUrl` | `string` | — | Override API base URL (testing) |
121
+
122
+ Attaches `req.agentVisa: VerifyResult & { token: string \| null }` to the request.
123
+
124
+ ---
125
+
126
+ ### `verify(token, options, headers?)` — standalone
127
+
128
+ ```typescript
129
+ const result = await verify(token, { widgetId, apiKey }, req.headers);
130
+ ```
131
+
132
+ Returns a `VerifyResult`:
133
+
134
+ | Field | Type | Description |
135
+ |-------|------|-------------|
136
+ | `valid` | `boolean` | Token is valid and human is verified |
137
+ | `humanVerified` | `boolean` | Alias for `valid` |
138
+ | `reason` | `string` | `'ok'` or error code |
139
+ | `verifiedAt` | `string` | ISO timestamp of human verification |
140
+ | `expiresAt` | `string` | ISO timestamp of token expiry |
141
+ | `domainVerified` | `boolean` | Requesting domain is verified by the Widget Holder |
142
+ | `webBotAuthBound` | `boolean` | Token was covered by RFC 9421 Signature-Input |
143
+ | `raw` | `object` | Raw AgentVisa API response |
144
+
145
+ ---
146
+
147
+ ### `extractToken(headers)` — utility
148
+
149
+ ```typescript
150
+ const { token, source } = extractToken(req.headers);
151
+ // source: 'assertion' | 'header' | null
152
+ // 'assertion' = AgentVisa-Assertion header (Web Bot Auth mode)
153
+ // 'header' = X-AgentVisa-Token header (standard mode)
154
+ ```
155
+
156
+ ---
157
+
158
+ ## How agents send the token
159
+
160
+ Agents use the [AgentVisa MCP server](https://github.com/AgentVisa-ai/agentvisa/tree/main/mcp) (`@agentvisa/mcp`) to get a `tmp_xxx` token, then send it in one of two ways:
161
+
162
+ **Standard mode:**
163
+ ```
164
+ X-AgentVisa-Token: tmp_xxxxxxxxxxxxxxxxxxxx
165
+ ```
166
+
167
+ **Web Bot Auth mode** (RFC 9421 — token bound in the signature):
168
+ ```
169
+ AgentVisa-Assertion: tmp_xxxxxxxxxxxxxxxxxxxx
170
+ Signature-Input: sig1=("@method" "@path" "host" "agentvisa-assertion");keyid="acme-bot-key";created=1234567890
171
+ Signature: sig1=:base64sig:
172
+ ```
173
+
174
+ ---
175
+
176
+ ## License
177
+
178
+ MIT · [agentvisa.ai](https://agentvisa.ai)
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @agentvisa/verify
3
+ *
4
+ * Verify human-authorized AI agents in one call.
5
+ * Works standalone or as Express middleware.
6
+ * Supports Web Bot Auth (RFC 9421) via AgentVisa-Assertion header.
7
+ *
8
+ * @example
9
+ * // Standalone
10
+ * import { extractToken, verify } from '@agentvisa/verify';
11
+ * const { token } = extractToken(req.headers);
12
+ * const result = await verify(token, { widgetId, apiKey });
13
+ *
14
+ * @example
15
+ * // Express middleware
16
+ * import { agentVisa } from '@agentvisa/verify';
17
+ * app.use('/api', agentVisa({ widgetId: 'wgt_xxx', apiKey: 'wk_xxx' }));
18
+ */
19
+ export { extractToken, verify } from './verify.js';
20
+ export { agentVisa } from './middleware.js';
21
+ export type { VerifyOptions, VerifyResult, MiddlewareOptions } from './types.js';
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @agentvisa/verify
3
+ *
4
+ * Verify human-authorized AI agents in one call.
5
+ * Works standalone or as Express middleware.
6
+ * Supports Web Bot Auth (RFC 9421) via AgentVisa-Assertion header.
7
+ *
8
+ * @example
9
+ * // Standalone
10
+ * import { extractToken, verify } from '@agentvisa/verify';
11
+ * const { token } = extractToken(req.headers);
12
+ * const result = await verify(token, { widgetId, apiKey });
13
+ *
14
+ * @example
15
+ * // Express middleware
16
+ * import { agentVisa } from '@agentvisa/verify';
17
+ * app.use('/api', agentVisa({ widgetId: 'wgt_xxx', apiKey: 'wk_xxx' }));
18
+ */
19
+ export { extractToken, verify } from './verify.js';
20
+ export { agentVisa } from './middleware.js';
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @agentvisa/verify — Express middleware
3
+ */
4
+ import type { Request, Response, NextFunction } from 'express';
5
+ import type { MiddlewareOptions, VerifyResult } from './types.js';
6
+ declare global {
7
+ namespace Express {
8
+ interface Request {
9
+ agentVisa?: VerifyResult & {
10
+ token: string | null;
11
+ };
12
+ }
13
+ }
14
+ }
15
+ /**
16
+ * Express middleware that verifies an incoming AgentVisa token.
17
+ *
18
+ * Reads the token from AgentVisa-Assertion (Web Bot Auth mode) or
19
+ * X-AgentVisa-Token (standard mode), calls the AgentVisa API, and
20
+ * either rejects the request (401) or attaches the result to req.agentVisa.
21
+ *
22
+ * @example
23
+ * // Reject unverified agents immediately
24
+ * app.use('/api', agentVisa({ widgetId: 'wgt_xxx', apiKey: 'wk_xxx' }));
25
+ *
26
+ * @example
27
+ * // Flag and decide in your handler
28
+ * app.use(agentVisa({ widgetId: 'wgt_xxx', apiKey: 'wk_xxx', onFail: 'flag' }));
29
+ * app.post('/checkout', (req, res) => {
30
+ * if (!req.agentVisa?.valid) return res.status(401).json({ error: 'human_required' });
31
+ * // ... proceed
32
+ * });
33
+ *
34
+ * @example
35
+ * // Web Bot Auth — check binding too
36
+ * app.use(agentVisa({ widgetId: 'wgt_xxx', apiKey: 'wk_xxx' }));
37
+ * app.post('/api', (req, res) => {
38
+ * const av = req.agentVisa!;
39
+ * // av.valid → human verified
40
+ * // av.webBotAuthBound → token was bound in RFC 9421 signature
41
+ * });
42
+ */
43
+ export declare function agentVisa(options: MiddlewareOptions): (req: Request, res: Response, next: NextFunction) => Promise<void>;
44
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAGlE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,SAAS,CAAC,EAAE,YAAY,GAAG;gBAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;aAAE,CAAC;SACrD;KACF;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,iBAAiB,IAIhD,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,MAAM,YAAY,KACjB,OAAO,CAAC,IAAI,CAAC,CA+CjB"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @agentvisa/verify — Express middleware
3
+ */
4
+ import { extractToken, verify } from './verify.js';
5
+ /**
6
+ * Express middleware that verifies an incoming AgentVisa token.
7
+ *
8
+ * Reads the token from AgentVisa-Assertion (Web Bot Auth mode) or
9
+ * X-AgentVisa-Token (standard mode), calls the AgentVisa API, and
10
+ * either rejects the request (401) or attaches the result to req.agentVisa.
11
+ *
12
+ * @example
13
+ * // Reject unverified agents immediately
14
+ * app.use('/api', agentVisa({ widgetId: 'wgt_xxx', apiKey: 'wk_xxx' }));
15
+ *
16
+ * @example
17
+ * // Flag and decide in your handler
18
+ * app.use(agentVisa({ widgetId: 'wgt_xxx', apiKey: 'wk_xxx', onFail: 'flag' }));
19
+ * app.post('/checkout', (req, res) => {
20
+ * if (!req.agentVisa?.valid) return res.status(401).json({ error: 'human_required' });
21
+ * // ... proceed
22
+ * });
23
+ *
24
+ * @example
25
+ * // Web Bot Auth — check binding too
26
+ * app.use(agentVisa({ widgetId: 'wgt_xxx', apiKey: 'wk_xxx' }));
27
+ * app.post('/api', (req, res) => {
28
+ * const av = req.agentVisa!;
29
+ * // av.valid → human verified
30
+ * // av.webBotAuthBound → token was bound in RFC 9421 signature
31
+ * });
32
+ */
33
+ export function agentVisa(options) {
34
+ const { onFail = 'reject', rejectBody, ...verifyOptions } = options;
35
+ return async function agentVisaMiddleware(req, res, next) {
36
+ const headers = req.headers;
37
+ const { token } = extractToken(headers);
38
+ if (!token) {
39
+ if (onFail === 'flag') {
40
+ req.agentVisa = {
41
+ valid: false,
42
+ humanVerified: false,
43
+ reason: 'no_token',
44
+ token: null,
45
+ };
46
+ next();
47
+ return;
48
+ }
49
+ res.status(401).json(rejectBody ?? {
50
+ error: 'agentvisa_required',
51
+ message: 'This endpoint requires an AgentVisa token. ' +
52
+ 'Set AgentVisa-Assertion (Web Bot Auth) or X-AgentVisa-Token header.',
53
+ widget_id: verifyOptions.widgetId,
54
+ });
55
+ return;
56
+ }
57
+ const result = await verify(token, verifyOptions, headers);
58
+ req.agentVisa = { ...result, token };
59
+ if (!result.valid) {
60
+ if (onFail === 'flag') {
61
+ next();
62
+ return;
63
+ }
64
+ res.status(401).json(rejectBody ?? {
65
+ error: 'agentvisa_invalid',
66
+ reason: result.reason,
67
+ message: 'AgentVisa verification failed.',
68
+ });
69
+ return;
70
+ }
71
+ next();
72
+ };
73
+ }
74
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAYnD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,SAAS,CAAC,OAA0B;IAClD,MAAM,EAAE,MAAM,GAAG,QAAQ,EAAE,UAAU,EAAE,GAAG,aAAa,EAAE,GAAG,OAAO,CAAC;IAEpE,OAAO,KAAK,UAAU,mBAAmB,CACvC,GAAY,EACZ,GAAa,EACb,IAAkB;QAElB,MAAM,OAAO,GAAG,GAAG,CAAC,OAAwD,CAAC;QAC7E,MAAM,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QAExC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACtB,GAAG,CAAC,SAAS,GAAG;oBACd,KAAK,EAAE,KAAK;oBACZ,aAAa,EAAE,KAAK;oBACpB,MAAM,EAAE,UAAU;oBAClB,KAAK,EAAE,IAAI;iBACZ,CAAC;gBACF,IAAI,EAAE,CAAC;gBACP,OAAO;YACT,CAAC;YACD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAClB,UAAU,IAAI;gBACZ,KAAK,EAAE,oBAAoB;gBAC3B,OAAO,EACL,6CAA6C;oBAC7C,qEAAqE;gBACvE,SAAS,EAAE,aAAa,CAAC,QAAQ;aAClC,CACF,CAAC;YACF,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;QAC3D,GAAG,CAAC,SAAS,GAAG,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC;QAErC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACtB,IAAI,EAAE,CAAC;gBACP,OAAO;YACT,CAAC;YACD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAClB,UAAU,IAAI;gBACZ,KAAK,EAAE,mBAAmB;gBAC1B,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,OAAO,EAAE,gCAAgC;aAC1C,CACF,CAAC;YACF,OAAO;QACT,CAAC;QAED,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @agentvisa/verify — TypeScript types
3
+ */
4
+ export interface VerifyOptions {
5
+ /** Widget ID from your AgentVisa dashboard (wgt_xxx) */
6
+ widgetId: string;
7
+ /** Widget API key from your AgentVisa dashboard (wk_xxx) */
8
+ apiKey: string;
9
+ /** Override the AgentVisa API base URL (default: https://api.agentvisa.ai) */
10
+ apiUrl?: string;
11
+ }
12
+ export interface VerifyResult {
13
+ /** Whether the AgentVisa token is valid */
14
+ valid: boolean;
15
+ /** Whether human verification passed (same as valid — future-proofing) */
16
+ humanVerified: boolean;
17
+ /** Reason code from AgentVisa API, or an internal error code */
18
+ reason: string;
19
+ /** ISO timestamp of when the human was verified */
20
+ verifiedAt?: string;
21
+ /** ISO timestamp of when this token expires */
22
+ expiresAt?: string;
23
+ /** Whether the requesting domain is verified by the Widget Holder */
24
+ domainVerified?: boolean;
25
+ /**
26
+ * Whether the AgentVisa-Assertion header was structurally bound in a
27
+ * Web Bot Auth (RFC 9421) Signature-Input.
28
+ *
29
+ * true = the token was covered by a Web Bot Auth signature (binding is present).
30
+ * The WAF/CDN (e.g. Cloudflare) is responsible for verifying the signature itself.
31
+ * false = token arrived via X-AgentVisa-Token (standard, non-bound mode).
32
+ * undefined = header inspection was not performed.
33
+ */
34
+ webBotAuthBound?: boolean;
35
+ /** Raw response body from the AgentVisa API */
36
+ raw?: Record<string, unknown>;
37
+ }
38
+ export interface MiddlewareOptions extends VerifyOptions {
39
+ /**
40
+ * What to do when verification fails:
41
+ * 'reject' — respond 401 immediately (default)
42
+ * 'flag' — set req.agentVisa and continue; let your handler decide
43
+ */
44
+ onFail?: 'reject' | 'flag';
45
+ /** Custom 401 response body when onFail = 'reject' */
46
+ rejectBody?: Record<string, unknown>;
47
+ }
48
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,2CAA2C;IAC3C,KAAK,EAAE,OAAO,CAAC;IACf,0EAA0E;IAC1E,aAAa,EAAE,OAAO,CAAC;IACvB,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD;;;;OAIG;IACH,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC3B,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @agentvisa/verify — TypeScript types
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @agentvisa/verify — core verification logic
3
+ */
4
+ import type { VerifyOptions, VerifyResult } from './types.js';
5
+ type Headers = Record<string, string | string[] | undefined>;
6
+ /**
7
+ * Extract the AgentVisa token from incoming request headers.
8
+ *
9
+ * Checks in order:
10
+ * 1. AgentVisa-Assertion — Web Bot Auth mode (token bound in RFC 9421 signature)
11
+ * 2. X-AgentVisa-Token — Standard mode
12
+ *
13
+ * Returns the token and which header it came from.
14
+ */
15
+ export declare function extractToken(headers: Headers): {
16
+ token: string | null;
17
+ source: 'assertion' | 'header' | null;
18
+ };
19
+ /**
20
+ * Verify an AgentVisa temporary token against the AgentVisa API.
21
+ *
22
+ * @param token The tmp_xxx token from the agent's request header
23
+ * @param options widgetId, apiKey, and optional apiUrl override
24
+ * @param headers Full request headers — used to detect Web Bot Auth binding
25
+ *
26
+ * @example
27
+ * // Standalone usage (any framework)
28
+ * const result = await verify(token, { widgetId, apiKey });
29
+ * if (!result.valid) return res.status(401).json({ error: result.reason });
30
+ */
31
+ export declare function verify(token: string, options: VerifyOptions, headers?: Headers): Promise<VerifyResult>;
32
+ export {};
33
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI9D,KAAK,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;AAuB7D;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG;IAC9C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,IAAI,CAAC;CACvC,CAQA;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,MAAM,CAC1B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,YAAY,CAAC,CAqDvB"}
package/dist/verify.js ADDED
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @agentvisa/verify — core verification logic
3
+ */
4
+ const DEFAULT_API_URL = 'https://api.agentvisa.ai';
5
+ function headerValue(headers, name) {
6
+ const val = headers[name.toLowerCase()];
7
+ if (!val)
8
+ return undefined;
9
+ return Array.isArray(val) ? val[0] : val;
10
+ }
11
+ /**
12
+ * Check whether the AgentVisa-Assertion header is covered by a
13
+ * Web Bot Auth (RFC 9421) Signature-Input.
14
+ *
15
+ * This is a structural check — confirms the token was included in the
16
+ * set of headers the agent signed, but does NOT verify the RFC 9421
17
+ * signature cryptography. Signature verification is handled by your
18
+ * WAF/CDN layer (e.g. Cloudflare Web Bot Auth).
19
+ */
20
+ function isWebBotAuthBound(headers) {
21
+ const sigInput = headerValue(headers, 'signature-input');
22
+ if (!sigInput)
23
+ return false;
24
+ return sigInput.toLowerCase().includes('"agentvisa-assertion"');
25
+ }
26
+ /**
27
+ * Extract the AgentVisa token from incoming request headers.
28
+ *
29
+ * Checks in order:
30
+ * 1. AgentVisa-Assertion — Web Bot Auth mode (token bound in RFC 9421 signature)
31
+ * 2. X-AgentVisa-Token — Standard mode
32
+ *
33
+ * Returns the token and which header it came from.
34
+ */
35
+ export function extractToken(headers) {
36
+ const assertion = headerValue(headers, 'agentvisa-assertion');
37
+ if (assertion)
38
+ return { token: assertion, source: 'assertion' };
39
+ const token = headerValue(headers, 'x-agentvisa-token');
40
+ if (token)
41
+ return { token, source: 'header' };
42
+ return { token: null, source: null };
43
+ }
44
+ /**
45
+ * Verify an AgentVisa temporary token against the AgentVisa API.
46
+ *
47
+ * @param token The tmp_xxx token from the agent's request header
48
+ * @param options widgetId, apiKey, and optional apiUrl override
49
+ * @param headers Full request headers — used to detect Web Bot Auth binding
50
+ *
51
+ * @example
52
+ * // Standalone usage (any framework)
53
+ * const result = await verify(token, { widgetId, apiKey });
54
+ * if (!result.valid) return res.status(401).json({ error: result.reason });
55
+ */
56
+ export async function verify(token, options, headers) {
57
+ const apiUrl = (options.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, '');
58
+ const webBotAuthBound = headers ? isWebBotAuthBound(headers) : undefined;
59
+ let response;
60
+ try {
61
+ response = await fetch(`${apiUrl}/v1/verify`, {
62
+ method: 'POST',
63
+ headers: {
64
+ 'Content-Type': 'application/json',
65
+ 'X-Widget-Api-Key': options.apiKey,
66
+ },
67
+ body: JSON.stringify({
68
+ token,
69
+ widget_id: options.widgetId,
70
+ }),
71
+ });
72
+ }
73
+ catch (err) {
74
+ return {
75
+ valid: false,
76
+ humanVerified: false,
77
+ reason: 'network_error',
78
+ webBotAuthBound,
79
+ raw: { error: String(err) },
80
+ };
81
+ }
82
+ let data = {};
83
+ try {
84
+ data = (await response.json());
85
+ }
86
+ catch {
87
+ // Non-JSON response — treat as error
88
+ return {
89
+ valid: false,
90
+ humanVerified: false,
91
+ reason: `http_${response.status}`,
92
+ webBotAuthBound,
93
+ raw: {},
94
+ };
95
+ }
96
+ const valid = response.ok && data.valid === true;
97
+ return {
98
+ valid,
99
+ humanVerified: valid,
100
+ reason: data.reason ?? (response.ok ? 'ok' : `http_${response.status}`),
101
+ verifiedAt: data.verified_at,
102
+ expiresAt: data.expires_at,
103
+ domainVerified: data.domain_verified,
104
+ webBotAuthBound,
105
+ raw: data,
106
+ };
107
+ }
108
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@agentvisa/verify",
3
+ "version": "0.1.0",
4
+ "description": "AgentVisa verifier — verify human-authorized AI agents in one call. Supports Web Bot Auth (RFC 9421) via AgentVisa-Assertion header.",
5
+ "keywords": [
6
+ "agentvisa",
7
+ "web-bot-auth",
8
+ "rfc9421",
9
+ "ai-agent",
10
+ "human-verification",
11
+ "express",
12
+ "middleware"
13
+ ],
14
+ "homepage": "https://agentvisa.ai",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/AgentVisa-ai/agentvisa.git"
18
+ },
19
+ "bugs": {
20
+ "url": "https://github.com/AgentVisa-ai/agentvisa/issues"
21
+ },
22
+ "license": "MIT",
23
+ "type": "module",
24
+ "main": "dist/index.js",
25
+ "types": "dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "import": "./dist/index.js",
29
+ "types": "./dist/index.d.ts"
30
+ }
31
+ },
32
+ "files": [
33
+ "dist"
34
+ ],
35
+ "scripts": {
36
+ "build": "tsc",
37
+ "dev": "tsc --watch",
38
+ "prepublishOnly": "npm run build"
39
+ },
40
+ "peerDependencies": {
41
+ "express": ">=4.0.0"
42
+ },
43
+ "peerDependenciesMeta": {
44
+ "express": {
45
+ "optional": true
46
+ }
47
+ },
48
+ "devDependencies": {
49
+ "@types/express": "^4.17.0",
50
+ "@types/node": "^22.0.0",
51
+ "typescript": "^5.5.0"
52
+ },
53
+ "engines": {
54
+ "node": ">=18.0.0"
55
+ }
56
+ }