@astrasyncai/verification-gateway 2.1.0 → 2.2.3
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 +64 -30
- package/dist/adapter-interface/interface.d.mts +2 -2
- package/dist/adapter-interface/interface.d.ts +2 -2
- package/dist/adapters/express.d.mts +2 -2
- package/dist/adapters/express.d.ts +2 -2
- package/dist/adapters/express.js +74 -95
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +74 -95
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +2 -2
- package/dist/adapters/nextjs.d.ts +2 -2
- package/dist/adapters/nextjs.js +74 -115
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +74 -115
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +2 -2
- package/dist/adapters/sdk.d.ts +2 -2
- package/dist/adapters/sdk.js +56 -55
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +56 -55
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.d.mts +2 -2
- package/dist/agent/index.d.ts +2 -2
- package/dist/agent/index.js +68 -2
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +66 -2
- package/dist/agent/index.mjs.map +1 -1
- package/dist/browser/background.js +56 -55
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +56 -55
- package/dist/browser/background.mjs.map +1 -1
- package/dist/browser/browser-adapter.d.mts +2 -2
- package/dist/browser/browser-adapter.d.ts +2 -2
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.d.ts +2 -2
- package/dist/cursor/cursor-adapter.d.mts +2 -2
- package/dist/cursor/cursor-adapter.d.ts +2 -2
- package/dist/cursor/extension.d.mts +2 -2
- package/dist/cursor/extension.d.ts +2 -2
- package/dist/cursor/extension.js +56 -55
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +56 -55
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/{express-Bcl-uBUE.d.ts → express-BtKlLI8U.d.ts} +2 -2
- package/dist/{express-CtwDIZyF.d.mts → express-DgwpS8Ha.d.mts} +2 -2
- package/dist/gateway/gateway.d.mts +2 -2
- package/dist/gateway/gateway.d.ts +2 -2
- package/dist/gateway/gateway.js +56 -55
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +56 -55
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +2 -2
- package/dist/git-trigger/git-hooks.d.ts +2 -2
- package/dist/{index-BY8yQ8N8.d.mts → index-AzhK20t0.d.mts} +46 -3
- package/dist/{index-CME6r4uH.d.ts → index-Ba0Lvsjo.d.ts} +1 -1
- package/dist/{index-3NRaBNvp.d.mts → index-BaxpmTGA.d.mts} +1 -1
- package/dist/{index-CtYSYwn3.d.ts → index-DpJS1JEI.d.ts} +46 -3
- package/dist/index.d.mts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +158 -117
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +158 -117
- package/dist/index.mjs.map +1 -1
- package/dist/local-evaluator/evaluator.d.mts +2 -2
- package/dist/local-evaluator/evaluator.d.ts +2 -2
- package/dist/{nextjs-CEldnIJ9.d.ts → nextjs-B2kg19c1.d.ts} +1 -1
- package/dist/{nextjs-BQyMCSx_.d.mts → nextjs-ZymQ8jDh.d.mts} +1 -1
- package/dist/{sdk-BhvuJSrH.d.mts → sdk-B7id0VFS.d.mts} +2 -2
- package/dist/{sdk-BlyVSC_S.d.ts → sdk-Bso0FSI0.d.ts} +2 -2
- package/dist/transport/index.d.mts +2 -2
- package/dist/transport/index.d.ts +2 -2
- package/dist/{types-79qS7aON.d.ts → types-BYKAY6Cc.d.ts} +1 -1
- package/dist/{types-jJnPXStc.d.mts → types-CgXPKUwi.d.mts} +1 -1
- package/dist/{types-CxQwJKbd.d.mts → types-DOrqNMgy.d.mts} +79 -13
- package/dist/{types-CxQwJKbd.d.ts → types-DOrqNMgy.d.ts} +79 -13
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/webhooks.d.mts +59 -0
- package/dist/webhooks.d.ts +59 -0
- package/dist/webhooks.js +81 -0
- package/dist/webhooks.js.map +1 -0
- package/dist/webhooks.mjs +55 -0
- package/dist/webhooks.mjs.map +1 -0
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
Universal Verification Gateway for AstraSync KYA Platform - verify AI agents across any counterparty type.
|
|
4
4
|
|
|
5
|
+
## Which package do I install?
|
|
6
|
+
|
|
7
|
+
AstraSync ships two npm packages with deliberately distinct roles. Pick by who you are, not by what you're building:
|
|
8
|
+
|
|
9
|
+
| You are… | Install | Use it for |
|
|
10
|
+
| --------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
11
|
+
| **A merchant / counterparty** running an API, MCP server, or website that AI agents call into | `@astrasyncai/verification-gateway` (this package) | Verifying inbound agents before they hit your endpoint. Express + Next.js middleware, Commerce Shield, webhook verifier. |
|
|
12
|
+
| **An agent author** building an AI agent that calls out to other people's services | `@astrasyncai/sdk` (the agent-side SDK on npm, separate repo) | Registering your agent with AstraSync, attaching credentials to outbound HTTP / MCP / A2A calls, KYD onboarding. |
|
|
13
|
+
| **A platform / orchestrator** doing both ends in one place | Both | The two roles compose: each side's flow is independent. |
|
|
14
|
+
|
|
15
|
+
> Both packages talk to the same backend — `POST /agents/verify-access`. The contract is shared; the role is just which side you're sitting on.
|
|
16
|
+
|
|
5
17
|
## Overview
|
|
6
18
|
|
|
7
19
|
The Verification Gateway provides a single, universal solution for verifying AI agents. One codebase, multiple deployment targets:
|
|
@@ -28,15 +40,17 @@ import { createMiddleware } from '@astrasyncai/verification-gateway/express';
|
|
|
28
40
|
|
|
29
41
|
const app = express();
|
|
30
42
|
|
|
31
|
-
app.use(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
app.use(
|
|
44
|
+
createMiddleware({
|
|
45
|
+
apiBaseUrl: 'https://astrasync.ai/api',
|
|
46
|
+
routes: [
|
|
47
|
+
{ pattern: '/api/public/*', method: '*', minAccessLevel: 'none' },
|
|
48
|
+
{ pattern: '/api/data/*', method: 'GET', minAccessLevel: 'read-only' },
|
|
49
|
+
{ pattern: '/api/data/*', method: '*', minAccessLevel: 'standard' },
|
|
50
|
+
{ pattern: '/api/admin/*', method: '*', minAccessLevel: 'internal' },
|
|
51
|
+
],
|
|
52
|
+
})
|
|
53
|
+
);
|
|
40
54
|
```
|
|
41
55
|
|
|
42
56
|
### Next.js Middleware
|
|
@@ -82,23 +96,23 @@ if (result.verified && result.accessLevel !== 'none') {
|
|
|
82
96
|
|
|
83
97
|
## Access Levels
|
|
84
98
|
|
|
85
|
-
| Level
|
|
86
|
-
|
|
87
|
-
| `none`
|
|
88
|
-
| `guidance`
|
|
89
|
-
| `read-only` | Can browse, no mutations
|
|
90
|
-
| `standard`
|
|
91
|
-
| `full`
|
|
92
|
-
| `internal`
|
|
99
|
+
| Level | Description |
|
|
100
|
+
| ----------- | --------------------------------- |
|
|
101
|
+
| `none` | No credentials provided |
|
|
102
|
+
| `guidance` | Commerce Shield overlay shown |
|
|
103
|
+
| `read-only` | Can browse, no mutations |
|
|
104
|
+
| `standard` | Normal access per PDLSS |
|
|
105
|
+
| `full` | Full access for high-trust agents |
|
|
106
|
+
| `internal` | Organization member access |
|
|
93
107
|
|
|
94
108
|
## Trust Levels
|
|
95
109
|
|
|
96
|
-
| Level
|
|
97
|
-
|
|
98
|
-
| BRONZE
|
|
99
|
-
| SILVER
|
|
100
|
-
| GOLD
|
|
101
|
-
| PLATINUM | 80-100
|
|
110
|
+
| Level | Score Range |
|
|
111
|
+
| -------- | ----------- |
|
|
112
|
+
| BRONZE | 0-39 |
|
|
113
|
+
| SILVER | 40-59 |
|
|
114
|
+
| GOLD | 60-79 |
|
|
115
|
+
| PLATINUM | 80-100 |
|
|
102
116
|
|
|
103
117
|
## UI Components
|
|
104
118
|
|
|
@@ -184,16 +198,36 @@ interface VerificationResult {
|
|
|
184
198
|
|
|
185
199
|
```typescript
|
|
186
200
|
interface GatewayConfig {
|
|
187
|
-
// Required
|
|
201
|
+
// Required. Always include the /api path prefix — for prod use
|
|
202
|
+
// 'https://astrasync.ai/api', for staging 'https://staging.astrasync.ai/api'.
|
|
188
203
|
apiBaseUrl: string;
|
|
189
204
|
|
|
190
205
|
// Optional
|
|
191
|
-
apiKey?: string;
|
|
192
|
-
defaultAccessLevel?: string;
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
206
|
+
apiKey?: string; // For authenticated requests
|
|
207
|
+
defaultAccessLevel?: string; // Default: 'guidance'
|
|
208
|
+
cacheTtl?: number; // Cache duration in seconds (default: 300)
|
|
209
|
+
debug?: boolean; // Enable debug logging
|
|
210
|
+
|
|
211
|
+
// Counterparty attribution (v2.2.3+)
|
|
212
|
+
counterpartyUrl?: string; // Sent with verify-access for analytics
|
|
213
|
+
counterpartyType?: 'agent' | 'api' | 'mcp_server' | 'website' | 'other' | 'unknown';
|
|
214
|
+
counterpartyId?: string; // Your ASTRAE-id (issued at endpoint registration);
|
|
215
|
+
// forwarded on every verify-access call so the server attributes traffic
|
|
216
|
+
// directly to this endpoint rather than resolving by URL.
|
|
217
|
+
|
|
218
|
+
// Init self-test (v2.2.3+) — fires a HEAD probe to verify-access on first
|
|
219
|
+
// call and warns if apiBaseUrl is pointing at HTML (catches the marketing-
|
|
220
|
+
// 404 case). Set true for tests where the extra request is undesirable.
|
|
221
|
+
disableInitChecks?: boolean;
|
|
222
|
+
|
|
223
|
+
// @deprecated — removed as functional config in v2.3.0. Server is the
|
|
224
|
+
// single source of truth for access-level decisions; the SDK reads
|
|
225
|
+
// access.accessLevel from the response verbatim. Setting these has no
|
|
226
|
+
// effect (a one-shot console.warn fires). To gate access to your
|
|
227
|
+
// endpoint, configure trust_score_requirement server-side via the
|
|
228
|
+
// /api/endpoints registration.
|
|
229
|
+
minTrustScore?: number;
|
|
230
|
+
minTrustScoreForFull?: number;
|
|
197
231
|
}
|
|
198
232
|
```
|
|
199
233
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AstraSyncGateway } from '../gateway/gateway.mjs';
|
|
2
|
-
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-
|
|
3
|
-
import '../types-
|
|
2
|
+
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-CgXPKUwi.mjs';
|
|
3
|
+
import '../types-DOrqNMgy.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* PlatformAdapter Interface
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AstraSyncGateway } from '../gateway/gateway.js';
|
|
2
|
-
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-
|
|
3
|
-
import '../types-
|
|
2
|
+
import { A as AgentAction, I as InterceptResult, P as PDLSSContext, V as VerificationDecision } from '../types-BYKAY6Cc.js';
|
|
3
|
+
import '../types-DOrqNMgy.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* PlatformAdapter Interface
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import 'express';
|
|
2
|
-
import '../types-
|
|
3
|
-
export { c as createMiddleware, a as extractAstraSyncCredentials, r as requireAccess, v as verifyOnly } from '../express-
|
|
2
|
+
import '../types-DOrqNMgy.mjs';
|
|
3
|
+
export { c as createMiddleware, a as extractAstraSyncCredentials, r as requireAccess, v as verifyOnly } from '../express-DgwpS8Ha.mjs';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import 'express';
|
|
2
|
-
import '../types-
|
|
3
|
-
export { c as createMiddleware, a as extractAstraSyncCredentials, r as requireAccess, v as verifyOnly } from '../express-
|
|
2
|
+
import '../types-DOrqNMgy.js';
|
|
3
|
+
export { c as createMiddleware, a as extractAstraSyncCredentials, r as requireAccess, v as verifyOnly } from '../express-BtKlLI8U.js';
|
package/dist/adapters/express.js
CHANGED
|
@@ -36,15 +36,6 @@ var ACCESS_LEVEL_HIERARCHY = {
|
|
|
36
36
|
full: 4,
|
|
37
37
|
internal: 5
|
|
38
38
|
};
|
|
39
|
-
var DEFAULT_TRUST_THRESHOLDS = {
|
|
40
|
-
none: 0,
|
|
41
|
-
guidance: 0,
|
|
42
|
-
"read-only": 20,
|
|
43
|
-
standard: 40,
|
|
44
|
-
full: 70,
|
|
45
|
-
internal: 0
|
|
46
|
-
// Internal is based on org membership, not score
|
|
47
|
-
};
|
|
48
39
|
function getTrustLevel(score) {
|
|
49
40
|
if (score >= 80) return "PLATINUM";
|
|
50
41
|
if (score >= 60) return "GOLD";
|
|
@@ -54,36 +45,39 @@ function getTrustLevel(score) {
|
|
|
54
45
|
function hasMinimumAccess(actual, required) {
|
|
55
46
|
return ACCESS_LEVEL_HIERARCHY[actual] >= ACCESS_LEVEL_HIERARCHY[required];
|
|
56
47
|
}
|
|
57
|
-
function getAccessLevelForScore(trustScore, thresholds = DEFAULT_TRUST_THRESHOLDS) {
|
|
58
|
-
if (trustScore >= thresholds.full) return "full";
|
|
59
|
-
if (trustScore >= thresholds.standard) return "standard";
|
|
60
|
-
if (trustScore >= thresholds["read-only"]) return "read-only";
|
|
61
|
-
return "guidance";
|
|
62
|
-
}
|
|
63
|
-
function determineAccessLevel(verified, trustScore, isOrgMember, customThresholds) {
|
|
64
|
-
if (!verified) {
|
|
65
|
-
return "guidance";
|
|
66
|
-
}
|
|
67
|
-
if (isOrgMember) {
|
|
68
|
-
return "internal";
|
|
69
|
-
}
|
|
70
|
-
const thresholds = {
|
|
71
|
-
...DEFAULT_TRUST_THRESHOLDS,
|
|
72
|
-
...customThresholds
|
|
73
|
-
};
|
|
74
|
-
return getAccessLevelForScore(trustScore, thresholds);
|
|
75
|
-
}
|
|
76
48
|
|
|
77
49
|
// src/verify.ts
|
|
78
50
|
var DEFAULT_CONFIG = {
|
|
79
|
-
apiBaseUrl: "https://
|
|
51
|
+
apiBaseUrl: "https://astrasync.ai/api",
|
|
80
52
|
defaultAccessLevel: "guidance",
|
|
81
|
-
minTrustScore
|
|
82
|
-
minTrustScoreForFull: 70,
|
|
53
|
+
// minTrustScore + minTrustScoreForFull deprecated in v2.3.0 — server decides.
|
|
83
54
|
cacheTtl: 300,
|
|
84
55
|
// 5 minutes
|
|
85
56
|
debug: false
|
|
86
57
|
};
|
|
58
|
+
var initCheckPerformed = false;
|
|
59
|
+
var deprecationWarningShown = false;
|
|
60
|
+
async function performInitCheck(apiBaseUrl, debug) {
|
|
61
|
+
initCheckPerformed = true;
|
|
62
|
+
try {
|
|
63
|
+
const probeUrl = `${apiBaseUrl}/agents/verify-access`;
|
|
64
|
+
const response = await fetch(probeUrl, { method: "HEAD" });
|
|
65
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
66
|
+
if (contentType.startsWith("text/html")) {
|
|
67
|
+
console.warn(
|
|
68
|
+
`[VerificationGateway] apiBaseUrl '${apiBaseUrl}' returned HTML (content-type: ${contentType}). This usually means apiBaseUrl is pointing at a marketing site instead of the API. Expected: 'https://astrasync.ai/api' (prod) or 'https://staging.astrasync.ai/api' (staging). Set disableInitChecks: true on GatewayConfig to silence this warning.`
|
|
69
|
+
);
|
|
70
|
+
} else if (debug) {
|
|
71
|
+
console.log(
|
|
72
|
+
`[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
} catch (err) {
|
|
76
|
+
if (debug) {
|
|
77
|
+
console.log(`[VerificationGateway] init check failed (non-blocking): ${String(err)}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
87
81
|
var verificationCache = /* @__PURE__ */ new Map();
|
|
88
82
|
function getCacheKey(credentials) {
|
|
89
83
|
return `${credentials.astraId || ""}-${credentials.apiKey || ""}-${credentials.jwt || ""}`;
|
|
@@ -108,7 +102,7 @@ function cacheResult(credentials, result, ttlSeconds) {
|
|
|
108
102
|
}
|
|
109
103
|
function extractCredentials(headers, query) {
|
|
110
104
|
const credentials = {};
|
|
111
|
-
const astraIdHeader = headers["x-astra-id"] || headers["X-Astra-Id"] || headers["X-ASTRA-ID"];
|
|
105
|
+
const astraIdHeader = headers["x-astra-id"] || headers["X-Astra-Id"] || headers["X-ASTRA-ID"] || headers["x-astra-agentid"] || headers["X-Astra-AgentId"] || headers["x-astra-agent-id"] || headers["X-Astra-Agent-Id"] || headers["X-ASTRA-AGENT-ID"];
|
|
112
106
|
if (astraIdHeader) {
|
|
113
107
|
credentials.astraId = Array.isArray(astraIdHeader) ? astraIdHeader[0] : astraIdHeader;
|
|
114
108
|
}
|
|
@@ -134,9 +128,6 @@ function extractCredentials(headers, query) {
|
|
|
134
128
|
}
|
|
135
129
|
return credentials;
|
|
136
130
|
}
|
|
137
|
-
function hasCredentials(credentials) {
|
|
138
|
-
return !!(credentials.astraId || credentials.apiKey || credentials.jwt);
|
|
139
|
-
}
|
|
140
131
|
function createGuidanceResponse(config, reason) {
|
|
141
132
|
const guidance = {
|
|
142
133
|
message: "This service verifies AI agents before granting access. Please register your agent with AstraSync.",
|
|
@@ -160,7 +151,7 @@ function createGuidanceResponse(config, reason) {
|
|
|
160
151
|
async function callVerifyAccessAPI(config, request) {
|
|
161
152
|
const { credentials, ...requestData } = request;
|
|
162
153
|
const body = {
|
|
163
|
-
agentId: credentials.astraId,
|
|
154
|
+
...credentials.astraId && { agentId: credentials.astraId },
|
|
164
155
|
purpose: requestData.purpose || "general"
|
|
165
156
|
};
|
|
166
157
|
if (requestData.action) body.action = requestData.action;
|
|
@@ -172,21 +163,34 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
172
163
|
if (requestData.isSubAgentRequest) body.isSubAgentRequest = requestData.isSubAgentRequest;
|
|
173
164
|
if (requestData.parentAgentId) body.parentAgentId = requestData.parentAgentId;
|
|
174
165
|
if (requestData.subAgentDepth !== void 0) body.subAgentDepth = requestData.subAgentDepth;
|
|
175
|
-
if (requestData.enableRuntimeChallenge)
|
|
166
|
+
if (requestData.enableRuntimeChallenge)
|
|
167
|
+
body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;
|
|
176
168
|
if (requestData.createSession) body.createSession = requestData.createSession;
|
|
177
169
|
if (requestData.durationRequired) body.durationRequired = requestData.durationRequired;
|
|
178
170
|
if (requestData.counterpartyType) body.counterpartyType = requestData.counterpartyType;
|
|
179
171
|
if (requestData.counterpartyUrl) body.counterpartyUrl = requestData.counterpartyUrl;
|
|
180
|
-
if (
|
|
172
|
+
if (config.counterpartyId) body.counterpartyId = config.counterpartyId;
|
|
173
|
+
if (requestData.runtimeChallengeOptions)
|
|
174
|
+
body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
|
|
175
|
+
if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
|
|
176
|
+
const meta = {
|
|
177
|
+
...requestData.clientIp && { sourceIp: requestData.clientIp },
|
|
178
|
+
...requestData.userAgent && { userAgent: requestData.userAgent },
|
|
179
|
+
...requestData.callerMetadata
|
|
180
|
+
};
|
|
181
|
+
if (Object.keys(meta).length > 0) body.callerMetadata = meta;
|
|
182
|
+
}
|
|
181
183
|
const headers = {
|
|
182
184
|
"Content-Type": "application/json",
|
|
183
185
|
...config.customHeaders
|
|
184
186
|
};
|
|
185
|
-
if (config.apiKey) {
|
|
186
|
-
headers["X-API-Key"] = config.apiKey;
|
|
187
|
-
}
|
|
188
187
|
if (credentials.authorizationHeader) {
|
|
189
188
|
headers["Authorization"] = credentials.authorizationHeader;
|
|
189
|
+
} else if (config.apiKey) {
|
|
190
|
+
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
191
|
+
}
|
|
192
|
+
if (config.apiKey) {
|
|
193
|
+
headers["X-API-Key"] = config.apiKey;
|
|
190
194
|
}
|
|
191
195
|
try {
|
|
192
196
|
const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
|
|
@@ -212,8 +216,14 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
212
216
|
}
|
|
213
217
|
async function verify(config, request) {
|
|
214
218
|
const mergedConfig = { ...DEFAULT_CONFIG, ...config };
|
|
215
|
-
if (!
|
|
216
|
-
|
|
219
|
+
if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
|
|
220
|
+
void performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug);
|
|
221
|
+
}
|
|
222
|
+
if (!deprecationWarningShown && (config.minTrustScore !== void 0 || config.minTrustScoreForFull !== void 0)) {
|
|
223
|
+
deprecationWarningShown = true;
|
|
224
|
+
console.warn(
|
|
225
|
+
"[VerificationGateway] minTrustScore / minTrustScoreForFull are deprecated in v2.3.0 and have no effect. Server is now the single source of truth for access-level decisions (the SDK reads access.accessLevel from the verify-access response). To gate access to an endpoint, configure the endpoint's trust_score_requirement server-side."
|
|
226
|
+
);
|
|
217
227
|
}
|
|
218
228
|
if (mergedConfig.cacheTtl && mergedConfig.cacheTtl > 0) {
|
|
219
229
|
const cached = getCachedResult(request.credentials);
|
|
@@ -285,18 +295,7 @@ async function verify(config, request) {
|
|
|
285
295
|
selfInstantiationAllowed: apiResponse.access.pdlss.selfInstantiationAllowed,
|
|
286
296
|
appliedPolicy: apiResponse.access.appliedPolicy
|
|
287
297
|
} : void 0;
|
|
288
|
-
const
|
|
289
|
-
const isOrgMember = false;
|
|
290
|
-
const accessLevel = determineAccessLevel(
|
|
291
|
-
true,
|
|
292
|
-
trustScore,
|
|
293
|
-
isOrgMember,
|
|
294
|
-
{
|
|
295
|
-
"read-only": 20,
|
|
296
|
-
standard: mergedConfig.minTrustScore || 40,
|
|
297
|
-
full: mergedConfig.minTrustScoreForFull || 70
|
|
298
|
-
}
|
|
299
|
-
);
|
|
298
|
+
const accessLevel = apiResponse.access?.accessLevel ?? "standard";
|
|
300
299
|
const result = {
|
|
301
300
|
verified: true,
|
|
302
301
|
accessLevel,
|
|
@@ -318,7 +317,9 @@ async function verify(config, request) {
|
|
|
318
317
|
if (result.recommendation === "deny") {
|
|
319
318
|
result.verified = false;
|
|
320
319
|
result.accessLevel = "none";
|
|
321
|
-
result.denialReasons = result.recommendationReasons || [
|
|
320
|
+
result.denialReasons = result.recommendationReasons || [
|
|
321
|
+
"Access denied by AstraSync recommendation"
|
|
322
|
+
];
|
|
322
323
|
if (result.runtimeChallenge) {
|
|
323
324
|
result.guidance = {
|
|
324
325
|
message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
|
|
@@ -340,7 +341,10 @@ async function verify(config, request) {
|
|
|
340
341
|
}
|
|
341
342
|
async function recordDecision(config, sessionId, decision, reason) {
|
|
342
343
|
const headers = { "Content-Type": "application/json" };
|
|
343
|
-
if (config.apiKey)
|
|
344
|
+
if (config.apiKey) {
|
|
345
|
+
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
346
|
+
headers["X-API-Key"] = config.apiKey;
|
|
347
|
+
}
|
|
344
348
|
await fetch(`${config.apiBaseUrl}/agents/verify-access/${sessionId}/decision`, {
|
|
345
349
|
method: "POST",
|
|
346
350
|
headers,
|
|
@@ -348,15 +352,6 @@ async function recordDecision(config, sessionId, decision, reason) {
|
|
|
348
352
|
}).catch(() => {
|
|
349
353
|
});
|
|
350
354
|
}
|
|
351
|
-
async function reportUnregisteredAttempt(config, data) {
|
|
352
|
-
const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
|
|
353
|
-
await fetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
|
|
354
|
-
method: "POST",
|
|
355
|
-
headers: { "Content-Type": "application/json" },
|
|
356
|
-
body: JSON.stringify(data)
|
|
357
|
-
}).catch(() => {
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
355
|
async function reportCounterpartyPreCheckFailure(config, data) {
|
|
361
356
|
const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
|
|
362
357
|
await fetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
|
|
@@ -541,32 +536,6 @@ function createMiddleware(options) {
|
|
|
541
536
|
return next();
|
|
542
537
|
}
|
|
543
538
|
const credentials = customExtractCredentials ? customExtractCredentials(req) : defaultExtractCredentials(req);
|
|
544
|
-
if (!hasCredentials(credentials) && routeConfig.minAccessLevel !== "guidance") {
|
|
545
|
-
const counterpartyUrl2 = config.counterpartyUrl || `${req.protocol}://${req.get("host")}`;
|
|
546
|
-
reportUnregisteredAttempt(config, {
|
|
547
|
-
counterpartyUrl: counterpartyUrl2,
|
|
548
|
-
counterpartyType: config.counterpartyType || "api",
|
|
549
|
-
sourceIp: req.ip,
|
|
550
|
-
userAgent: req.headers["user-agent"],
|
|
551
|
-
requestPath: req.path,
|
|
552
|
-
requestMethod: req.method
|
|
553
|
-
}).catch(() => {
|
|
554
|
-
});
|
|
555
|
-
const result2 = {
|
|
556
|
-
verified: false,
|
|
557
|
-
accessLevel: "none",
|
|
558
|
-
denialReasons: ["No agent credentials provided"],
|
|
559
|
-
guidance: {
|
|
560
|
-
message: "This endpoint requires agent verification. Please provide your ASTRA-ID.",
|
|
561
|
-
registrationUrl: `${config.apiBaseUrl?.replace("/api", "")}/register`,
|
|
562
|
-
documentationUrl: `${config.apiBaseUrl?.replace("/api", "")}/docs/agent-access`
|
|
563
|
-
},
|
|
564
|
-
verifiedAt: /* @__PURE__ */ new Date()
|
|
565
|
-
};
|
|
566
|
-
req.agentVerification = result2;
|
|
567
|
-
onDenied(result2, req, res);
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
539
|
const purpose = customExtractPurpose ? customExtractPurpose(req) : defaultExtractPurpose(req);
|
|
571
540
|
const astraCreds = extractAstraSyncCredentials(req);
|
|
572
541
|
const counterpartyUrl = config.counterpartyUrl || `${req.protocol}://${req.get("host")}`;
|
|
@@ -597,18 +566,28 @@ function createMiddleware(options) {
|
|
|
597
566
|
return;
|
|
598
567
|
}
|
|
599
568
|
const shouldRecordDecisions = recordDecisions !== false;
|
|
569
|
+
const forwardedFor = req.headers["x-forwarded-for"];
|
|
570
|
+
const forwardedForStr = Array.isArray(forwardedFor) ? forwardedFor.join(", ") : forwardedFor;
|
|
571
|
+
const originalClientIp = forwardedForStr ? forwardedForStr.split(",")[0].trim() : req.ip;
|
|
572
|
+
const agentCardUrl = typeof req.headers["x-astrasync-agent-card"] === "string" ? req.headers["x-astrasync-agent-card"] : void 0;
|
|
600
573
|
const result = await verify(config, {
|
|
601
574
|
credentials,
|
|
602
575
|
purpose,
|
|
603
576
|
action: req.method.toLowerCase(),
|
|
604
577
|
resource: req.path,
|
|
605
|
-
clientIp: req.ip,
|
|
606
|
-
userAgent: req.headers["user-agent"],
|
|
607
578
|
createSession: shouldRecordDecisions,
|
|
608
579
|
counterpartyUrl,
|
|
609
580
|
counterpartyType: config.counterpartyType || "api",
|
|
610
581
|
enableRuntimeChallenge,
|
|
611
|
-
durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration
|
|
582
|
+
durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration,
|
|
583
|
+
callerMetadata: {
|
|
584
|
+
sourceIp: originalClientIp,
|
|
585
|
+
userAgent: req.headers["user-agent"],
|
|
586
|
+
referer: req.headers.referer,
|
|
587
|
+
host: req.headers.host,
|
|
588
|
+
forwardedFor: forwardedForStr,
|
|
589
|
+
agentCardUrl
|
|
590
|
+
}
|
|
612
591
|
});
|
|
613
592
|
req.agentVerification = result;
|
|
614
593
|
const sessionId = result.sessionId;
|