auth-agents 0.4.0 → 0.4.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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Auth-Agents
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Auth-Agents
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,257 +1,278 @@
1
- # auth-agents
2
-
3
- Verify AI agent identities with [Agent Auth](https://getagentauth.com). DID-based authentication using Ed25519 and Verifiable Credentials.
4
-
5
- ## Install
6
-
7
- ```bash
8
- npm install auth-agents
9
- ```
10
-
11
- ## Quick Start — Verify a Credential
12
-
13
- ```typescript
14
- import { AuthAgents } from "auth-agents"
15
-
16
- const client = new AuthAgents()
17
-
18
- const result = await client.verify("eyJhbGciOiJFZERTQSJ9...")
19
-
20
- if (result.valid) {
21
- console.log(result.did) // "did:key:z6Mk..."
22
- console.log(result.agent_name) // "Claude"
23
- console.log(result.agent_model) // "claude-opus-4-6"
24
- console.log(result.agent_provider) // "Anthropic"
25
- console.log(result.agent_purpose) // "Research assistant"
26
- console.log(result.key_origin) // "server_generated" | "client_provided"
27
- console.log(result.expires_at) // "2026-02-27T01:58:15.000Z"
28
- }
29
- ```
30
-
31
- ## Identity Registration Flows
32
-
33
- Agent Auth supports two registration paths. Both produce the same DID, credential, and challenge-response authentication. The difference is who holds the private key.
34
-
35
- ### Flow A — Server-Generated Keys (zero friction)
36
-
37
- The server generates an Ed25519 key pair. You receive the private key once and must store it securely. `key_origin` will be `"server_generated"`.
38
-
39
- ```typescript
40
- import { AuthAgents } from "auth-agents"
41
-
42
- const client = new AuthAgents()
43
-
44
- // 1. Register — server generates keys
45
- const identity = await client.register({
46
- agent_name: "Claude",
47
- agent_model: "claude-opus-4-6",
48
- agent_provider: "Anthropic",
49
- agent_purpose: "Research assistant",
50
- })
51
- // identity.did — "did:key:z6Mk..."
52
- // identity.credential — VC-JWT (present to websites)
53
- // identity.key_origin — "server_generated"
54
- // identity.private_key_jwk — SAVE THIS. Server does not keep it.
55
-
56
- // 2. Request a challenge
57
- const challenge = await client.challenge(identity.did)
58
-
59
- // 3. Sign the nonce with the private key
60
- const signature = await AuthAgents.signChallenge(
61
- identity.private_key_jwk!,
62
- challenge.nonce
63
- )
64
-
65
- // 4. Authenticate and receive a fresh credential
66
- const auth = await client.authenticate({
67
- challenge_id: challenge.challenge_id,
68
- did: identity.did,
69
- signature,
70
- })
71
-
72
- if (auth.valid) {
73
- console.log(auth.credential) // fresh VC-JWT
74
- console.log(auth.session_token) // session ID
75
- }
76
- ```
77
-
78
- ### Flow B — Bring Your Own Key (BYOK)
79
-
80
- Generate the key pair locally. The private key never leaves your process. `key_origin` will be `"client_provided"`.
81
-
82
- ```typescript
83
- import { AuthAgents } from "auth-agents"
84
-
85
- const client = new AuthAgents()
86
-
87
- // 1. Generate an Ed25519 key pair locally
88
- const keyPair = await AuthAgents.generateKeyPair()
89
- // keyPair.publicKeyJwk — { kty, crv, x }
90
- // keyPair.privateKeyJwk — { kty, crv, x, d } ← never sent to server
91
-
92
- // 2. Register with your public key (no private_key_jwk returned)
93
- const identity = await client.register({
94
- agent_name: "Claude",
95
- agent_model: "claude-opus-4-6",
96
- agent_provider: "Anthropic",
97
- agent_purpose: "Research assistant",
98
- public_key_jwk: keyPair.publicKeyJwk,
99
- })
100
- // identity.did — "did:key:z6Mk..."
101
- // identity.credential — VC-JWT
102
- // identity.key_origin — "client_provided"
103
-
104
- // 3. Request a challenge
105
- const challenge = await client.challenge(identity.did)
106
-
107
- // 4. Sign the nonce with your private key
108
- const signature = await AuthAgents.signChallenge(
109
- keyPair.privateKeyJwk,
110
- challenge.nonce
111
- )
112
-
113
- // 5. Authenticate and receive a fresh credential
114
- const auth = await client.authenticate({
115
- challenge_id: challenge.challenge_id,
116
- did: identity.did,
117
- signature,
118
- })
119
-
120
- if (auth.valid) {
121
- console.log(auth.credential) // fresh VC-JWT
122
- console.log(auth.session_token) // session ID
123
- }
124
- ```
125
-
126
- ## Website Integration (Next.js)
127
-
128
- ```typescript
129
- // app/api/auth/agent/route.ts
130
- import { AuthAgents } from "auth-agents"
131
-
132
- const authAgents = new AuthAgents()
133
-
134
- export async function POST(request: Request) {
135
- const { credential } = await request.json()
136
-
137
- const result = await authAgents.verify(credential)
138
-
139
- if (!result.valid) {
140
- return Response.json({ error: result.message }, { status: 401 })
141
- }
142
-
143
- // Create a session with the verified agent identity
144
- const sessionId = crypto.randomUUID()
145
- await db.insert("sessions", {
146
- session_id: sessionId,
147
- did: result.did,
148
- agent_name: result.agent_name,
149
- agent_model: result.agent_model,
150
- key_origin: result.key_origin,
151
- expires_at: result.expires_at,
152
- })
153
-
154
- return Response.json({ authenticated: true, session_id: sessionId })
155
- }
156
- ```
157
-
158
- ## Website Integration (Express.js)
159
-
160
- ```typescript
161
- import express from "express"
162
- import { AuthAgents } from "auth-agents"
163
-
164
- const app = express()
165
- const authAgents = new AuthAgents()
166
-
167
- app.post("/auth/agent", express.json(), async (req, res) => {
168
- const { credential } = req.body
169
- const result = await authAgents.verify(credential)
170
-
171
- if (!result.valid) {
172
- return res.status(401).json({ error: result.message })
173
- }
174
-
175
- // Agent verified — create session
176
- req.session.agent = {
177
- did: result.did,
178
- name: result.agent_name,
179
- model: result.agent_model,
180
- key_origin: result.key_origin,
181
- }
182
-
183
- res.json({ authenticated: true, agent_name: result.agent_name })
184
- })
185
- ```
186
-
187
- ## API
188
-
189
- ### `new AuthAgents(config?)`
190
-
191
- - `config.baseUrl` — API base URL (default: `https://auth.getagentauth.com`)
192
-
193
- ### `AuthAgents.generateKeyPair()` — Static
194
-
195
- Generate a local Ed25519 key pair using the Web Crypto API. No network call.
196
-
197
- Returns `Ed25519KeyPair`:
198
- ```typescript
199
- {
200
- publicKeyJwk: { kty: string; crv: string; x: string }
201
- privateKeyJwk: { kty: string; crv: string; x: string; d: string }
202
- }
203
- ```
204
-
205
- ### `AuthAgents.signChallenge(privateKeyJwk, nonce)` — Static
206
-
207
- Sign an authentication challenge nonce with an Ed25519 private key. No network call.
208
-
209
- - `privateKeyJwk` — JWK with `d` parameter (the private key from `generateKeyPair()` or from `register()`)
210
- - `nonce` — the nonce string from `client.challenge()`
211
-
212
- Returns a `Promise<string>` — base64url-encoded Ed25519 signature.
213
-
214
- ### `client.verify(credential)` — Verify a VC-JWT credential
215
-
216
- Returns `VerifyResult` on success:
217
- ```typescript
218
- {
219
- valid: true
220
- did: string
221
- agent_name: string | null
222
- agent_model: string | null
223
- agent_provider: string | null
224
- agent_purpose: string | null
225
- key_fingerprint: string | null
226
- key_origin: string | null // "server_generated" | "client_provided"
227
- issued_at: string | null
228
- expires_at: string | null
229
- }
230
- ```
231
-
232
- ### `client.register(input)` Register a new agent identity
233
-
234
- `input.public_key_jwk` is optional. Omit it for server-generated keys (Flow A). Provide it for BYOK (Flow B).
235
-
1
+ # auth-agents
2
+
3
+ Verify AI agent identities with [Agent Auth](https://usevigil.dev). DID-based authentication using Ed25519 and Verifiable Credentials.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install auth-agents
9
+ ```
10
+
11
+ ## Quick Start — Verify a Credential
12
+
13
+ ```typescript
14
+ import { AuthAgents } from "auth-agents"
15
+
16
+ const client = new AuthAgents()
17
+
18
+ const result = await client.verify("eyJhbGciOiJFZERTQSJ9...")
19
+
20
+ if (result.valid) {
21
+ console.log(result.did) // "did:key:z6Mk..."
22
+ console.log(result.agent_name) // "Claude"
23
+ console.log(result.agent_model) // "claude-opus-4-6"
24
+ console.log(result.agent_provider) // "Anthropic"
25
+ console.log(result.agent_purpose) // "Research assistant"
26
+ console.log(result.key_origin) // "server_generated" | "client_provided"
27
+ console.log(result.expires_at) // "2026-02-27T01:58:15.000Z"
28
+ }
29
+ ```
30
+
31
+ ## Identity Registration Flows
32
+
33
+ Agent Auth supports two registration paths. Both produce the same DID, credential, and challenge-response authentication. The difference is who holds the private key.
34
+
35
+ ### Flow A — Server-Generated Keys (zero friction)
36
+
37
+ The server generates an Ed25519 key pair. You receive the private key once and must store it securely. `key_origin` will be `"server_generated"`.
38
+
39
+ ```typescript
40
+ import { AuthAgents } from "auth-agents"
41
+
42
+ const client = new AuthAgents()
43
+
44
+ // 1. Register — server generates keys
45
+ const identity = await client.register({
46
+ agent_name: "Claude",
47
+ agent_model: "claude-opus-4-6",
48
+ agent_provider: "Anthropic",
49
+ agent_purpose: "Research assistant",
50
+ })
51
+ // identity.did — "did:key:z6Mk..."
52
+ // identity.credential — VC-JWT (present to websites)
53
+ // identity.key_origin — "server_generated"
54
+ // identity.private_key_jwk — SAVE THIS. Server does not keep it.
55
+
56
+ // 2. Request a challenge
57
+ const challenge = await client.challenge(identity.did)
58
+
59
+ // 3. Sign the nonce with the private key
60
+ const signature = await AuthAgents.signChallenge(
61
+ identity.private_key_jwk!,
62
+ challenge.nonce
63
+ )
64
+
65
+ // 4. Authenticate and receive a fresh credential
66
+ const auth = await client.authenticate({
67
+ challenge_id: challenge.challenge_id,
68
+ did: identity.did,
69
+ signature,
70
+ })
71
+
72
+ if (auth.valid) {
73
+ console.log(auth.credential) // fresh VC-JWT
74
+ console.log(auth.session_token) // session ID
75
+ }
76
+ ```
77
+
78
+ ### Flow B — Bring Your Own Key (BYOK)
79
+
80
+ Generate the key pair locally. The private key never leaves your process. `key_origin` will be `"client_provided"`.
81
+
82
+ ```typescript
83
+ import { AuthAgents } from "auth-agents"
84
+
85
+ const client = new AuthAgents()
86
+
87
+ // 1. Generate an Ed25519 key pair locally
88
+ const keyPair = await AuthAgents.generateKeyPair()
89
+ // keyPair.publicKeyJwk — { kty, crv, x }
90
+ // keyPair.privateKeyJwk — { kty, crv, x, d } ← never sent to server
91
+
92
+ // 2. Register with your public key (no private_key_jwk returned)
93
+ const identity = await client.register({
94
+ agent_name: "Claude",
95
+ agent_model: "claude-opus-4-6",
96
+ agent_provider: "Anthropic",
97
+ agent_purpose: "Research assistant",
98
+ public_key_jwk: keyPair.publicKeyJwk,
99
+ })
100
+ // identity.did — "did:key:z6Mk..."
101
+ // identity.credential — VC-JWT
102
+ // identity.key_origin — "client_provided"
103
+
104
+ // 3. Request a challenge
105
+ const challenge = await client.challenge(identity.did)
106
+
107
+ // 4. Sign the nonce with your private key
108
+ const signature = await AuthAgents.signChallenge(
109
+ keyPair.privateKeyJwk,
110
+ challenge.nonce
111
+ )
112
+
113
+ // 5. Authenticate and receive a fresh credential
114
+ const auth = await client.authenticate({
115
+ challenge_id: challenge.challenge_id,
116
+ did: identity.did,
117
+ signature,
118
+ })
119
+
120
+ if (auth.valid) {
121
+ console.log(auth.credential) // fresh VC-JWT
122
+ console.log(auth.session_token) // session ID
123
+ }
124
+ ```
125
+
126
+ ## Website Integration (Next.js)
127
+
128
+ ```typescript
129
+ // app/api/auth/agent-login/route.ts
130
+ import { AuthAgents } from "auth-agents"
131
+
132
+ const authAgents = new AuthAgents()
133
+
134
+ export async function POST(request: Request) {
135
+ const { credential } = await request.json()
136
+
137
+ const result = await authAgents.verify(credential)
138
+
139
+ if (!result.valid) {
140
+ return Response.json({ error: result.message }, { status: 401 })
141
+ }
142
+
143
+ // Create a session with the verified agent identity
144
+ const sessionId = crypto.randomUUID()
145
+ await db.insert("sessions", {
146
+ session_id: sessionId,
147
+ did: result.did,
148
+ agent_name: result.agent_name,
149
+ agent_model: result.agent_model,
150
+ key_origin: result.key_origin,
151
+ expires_at: result.expires_at,
152
+ })
153
+
154
+ return Response.json({ authenticated: true, session_id: sessionId })
155
+ }
156
+ ```
157
+
158
+ ## Website Integration (Express.js)
159
+
160
+ ```typescript
161
+ import express from "express"
162
+ import { AuthAgents } from "auth-agents"
163
+
164
+ const app = express()
165
+ const authAgents = new AuthAgents()
166
+
167
+ app.post("/auth/agent-login", express.json(), async (req, res) => {
168
+ const { credential } = req.body
169
+ const result = await authAgents.verify(credential)
170
+
171
+ if (!result.valid) {
172
+ return res.status(401).json({ error: result.message })
173
+ }
174
+
175
+ // Agent verified — create session
176
+ req.session.agent = {
177
+ did: result.did,
178
+ name: result.agent_name,
179
+ model: result.agent_model,
180
+ key_origin: result.key_origin,
181
+ }
182
+
183
+ res.json({ authenticated: true, agent_name: result.agent_name })
184
+ })
185
+ ```
186
+
187
+ ## API
188
+
189
+ ### `new AuthAgents(config?)`
190
+
191
+ - `config.baseUrl` — API base URL (default: `https://auth.usevigil.dev`). The SDK enforces HTTPS for all API communication. HTTP is only allowed for `localhost` during development.
192
+
193
+ ### `AuthAgents.generateKeyPair()` — Static
194
+
195
+ Generate a local Ed25519 key pair using the Web Crypto API. No network call.
196
+
197
+ Returns `Ed25519KeyPair`:
198
+ ```typescript
199
+ {
200
+ publicKeyJwk: { kty: string; crv: string; x: string }
201
+ privateKeyJwk: { kty: string; crv: string; x: string; d: string }
202
+ }
203
+ ```
204
+
205
+ ### `AuthAgents.signChallenge(privateKeyJwk, nonce)` — Static
206
+
207
+ Sign an authentication challenge nonce with an Ed25519 private key. No network call.
208
+
209
+ - `privateKeyJwk` — JWK with `d` parameter (the private key from `generateKeyPair()` or from `register()`)
210
+ - `nonce` — the nonce string from `client.challenge()`
211
+
212
+ Returns a `Promise<string>` — base64url-encoded Ed25519 signature.
213
+
214
+ ### `client.verify(credential)` — Verify a VC-JWT credential
215
+
216
+ Returns `VerifyResult` on success:
217
+ ```typescript
218
+ {
219
+ valid: true
220
+ did: string
221
+ agent_name: string | null
222
+ agent_model: string | null
223
+ agent_provider: string | null
224
+ agent_purpose: string | null
225
+ key_fingerprint: string | null
226
+ key_origin: string | null // "server_generated" | "client_provided"
227
+ issued_at: string | null
228
+ expires_at: string | null
229
+ }
230
+ ```
231
+
232
+ Returns `VerifyError` (HTTP 401) without throwing:
233
+ ```typescript
234
+ {
235
+ valid: false
236
+ error: "credential_expired" | "invalid_issuer" | "signature_invalid" | "credential_revoked"
237
+ message: string
238
+ }
239
+ ```
240
+
241
+ ### `client.register(input)` — Register a new agent identity
242
+
243
+ `input.public_key_jwk` is optional. Omit it for server-generated keys (Flow A). Provide it for BYOK (Flow B).
244
+ You can also pass:
245
+ - `metadata` — key/value metadata map (max key/value sizes enforced server-side)
246
+
236
247
  Returns `RegisterResult`:
237
248
  ```typescript
238
249
  {
239
250
  did: string
240
- credential: string
241
- key_fingerprint: string
251
+ credential: string
252
+ key_fingerprint: string
242
253
  key_origin?: "server_generated" | "client_provided"
243
254
  private_key_jwk?: { kty, crv, x, d } // only present for server_generated
244
255
  }
245
256
  ```
246
257
 
247
- ### `client.challenge(did)` Request an auth challenge
258
+ Registration always returns a credential with the server default lifetime (24 hours).
259
+ If you need a different lifetime, pass `credential_expires_in` to `client.challenge(...)`.
248
260
 
249
- ### `client.authenticate(input)` — Submit signed challenge
261
+ ### `client.challenge(did, site_id?, credential_expires_in?)` — Request an auth challenge
250
262
 
251
- ## Documentation
263
+ `site_id` is optional and scopes the challenge/session when your deployment uses site-level org provisioning.
252
264
 
253
- Full API reference at [getagentauth.com/docs](https://getagentauth.com/docs/)
265
+ `credential_expires_in` is optional and allows website developers to set the credential lifetime in seconds for the resulting authentication. Use `0` for non-expiring credentials. Min 300, max 2592000.
254
266
 
255
- ## License
267
+ ### `client.authenticate(input)` — Submit signed challenge
256
268
 
257
- MIT - Agent Auth
269
+ `input` contains `challenge_id`, `did`, and `signature` (base64url-encoded).
270
+ The credential returned from `client.authenticate(...)` uses the lifetime chosen in the preceding `client.challenge(...)` call.
271
+
272
+ ## Documentation
273
+
274
+ Full API reference at [usevigil.dev/docs](https://usevigil.dev/docs/)
275
+
276
+ ## License
277
+
278
+ MIT - Agent Auth
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  interface AuthAgentsConfig {
2
- /** Base URL of the Agent Auth API. Defaults to https://auth.getagentauth.com */
2
+ /** Base URL of the Agent Auth API. Defaults to https://auth.usevigil.dev */
3
3
  baseUrl?: string;
4
4
  }
5
5
  /** Ed25519 key pair in JWK format, returned by generateKeyPair() */
@@ -30,7 +30,7 @@ interface VerifyResult {
30
30
  }
31
31
  interface VerifyError {
32
32
  valid: false;
33
- error: "credential_expired" | "invalid_issuer" | "signature_invalid";
33
+ error: "credential_expired" | "invalid_issuer" | "signature_invalid" | "credential_revoked";
34
34
  message: string;
35
35
  }
36
36
  type VerifyResponse = VerifyResult | VerifyError;
@@ -44,6 +44,7 @@ interface RegisterInput {
44
44
  crv: string;
45
45
  x: string;
46
46
  };
47
+ metadata?: Record<string, string>;
47
48
  }
48
49
  interface RegisterResult {
49
50
  did: string;
@@ -120,7 +121,8 @@ declare class AuthAgents {
120
121
  * Verify a VC-JWT credential issued by Agent Auth.
121
122
  *
122
123
  * @param credential - The VC-JWT string from the agent
123
- * @returns Verified agent identity or error details
124
+ * @returns Verified agent identity. If API returns 401, returns
125
+ * `{ valid: false, error, message }` instead of throwing.
124
126
  */
125
127
  verify(credential: string): Promise<VerifyResponse>;
126
128
  /**
@@ -136,14 +138,17 @@ declare class AuthAgents {
136
138
  * Request an authentication challenge nonce.
137
139
  *
138
140
  * @param did - The agent's DID
141
+ * @param site_id - Optional site scope for provisioned deployments
142
+ * @param credential_expires_in - Optional credential lifetime in seconds (set by website developer). Use 0 for non-expiring. Min 300, max 2592000.
139
143
  * @returns Challenge ID and nonce to sign
140
144
  */
141
- challenge(did: string): Promise<ChallengeResult>;
145
+ challenge(did: string, site_id?: string, credential_expires_in?: number): Promise<ChallengeResult>;
142
146
  /**
143
147
  * Submit a signed challenge to authenticate and receive a fresh credential.
144
148
  *
145
149
  * @param input - challenge_id, did, and base64url signature
146
- * @returns Session token and fresh VC-JWT credential
150
+ * @returns Session token and fresh VC-JWT credential. If API returns 401,
151
+ * returns `{ valid: false, error, message }` instead of throwing.
147
152
  */
148
153
  authenticate(input: AuthVerifyInput): Promise<AuthVerifyResponse>;
149
154
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  interface AuthAgentsConfig {
2
- /** Base URL of the Agent Auth API. Defaults to https://auth.getagentauth.com */
2
+ /** Base URL of the Agent Auth API. Defaults to https://auth.usevigil.dev */
3
3
  baseUrl?: string;
4
4
  }
5
5
  /** Ed25519 key pair in JWK format, returned by generateKeyPair() */
@@ -30,7 +30,7 @@ interface VerifyResult {
30
30
  }
31
31
  interface VerifyError {
32
32
  valid: false;
33
- error: "credential_expired" | "invalid_issuer" | "signature_invalid";
33
+ error: "credential_expired" | "invalid_issuer" | "signature_invalid" | "credential_revoked";
34
34
  message: string;
35
35
  }
36
36
  type VerifyResponse = VerifyResult | VerifyError;
@@ -44,6 +44,7 @@ interface RegisterInput {
44
44
  crv: string;
45
45
  x: string;
46
46
  };
47
+ metadata?: Record<string, string>;
47
48
  }
48
49
  interface RegisterResult {
49
50
  did: string;
@@ -120,7 +121,8 @@ declare class AuthAgents {
120
121
  * Verify a VC-JWT credential issued by Agent Auth.
121
122
  *
122
123
  * @param credential - The VC-JWT string from the agent
123
- * @returns Verified agent identity or error details
124
+ * @returns Verified agent identity. If API returns 401, returns
125
+ * `{ valid: false, error, message }` instead of throwing.
124
126
  */
125
127
  verify(credential: string): Promise<VerifyResponse>;
126
128
  /**
@@ -136,14 +138,17 @@ declare class AuthAgents {
136
138
  * Request an authentication challenge nonce.
137
139
  *
138
140
  * @param did - The agent's DID
141
+ * @param site_id - Optional site scope for provisioned deployments
142
+ * @param credential_expires_in - Optional credential lifetime in seconds (set by website developer). Use 0 for non-expiring. Min 300, max 2592000.
139
143
  * @returns Challenge ID and nonce to sign
140
144
  */
141
- challenge(did: string): Promise<ChallengeResult>;
145
+ challenge(did: string, site_id?: string, credential_expires_in?: number): Promise<ChallengeResult>;
142
146
  /**
143
147
  * Submit a signed challenge to authenticate and receive a fresh credential.
144
148
  *
145
149
  * @param input - challenge_id, did, and base64url signature
146
- * @returns Session token and fresh VC-JWT credential
150
+ * @returns Session token and fresh VC-JWT credential. If API returns 401,
151
+ * returns `{ valid: false, error, message }` instead of throwing.
147
152
  */
148
153
  authenticate(input: AuthVerifyInput): Promise<AuthVerifyResponse>;
149
154
  }
package/dist/index.js CHANGED
@@ -24,10 +24,20 @@ __export(index_exports, {
24
24
  verify: () => verify
25
25
  });
26
26
  module.exports = __toCommonJS(index_exports);
27
- var DEFAULT_BASE_URL = "https://auth.getagentauth.com";
27
+ var DEFAULT_BASE_URL = "https://auth.usevigil.dev";
28
28
  var AuthAgents = class {
29
29
  constructor(config) {
30
- this.baseUrl = (config?.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
30
+ const url = (config?.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
31
+ try {
32
+ const parsed = new URL(url);
33
+ if (parsed.protocol !== "https:" && parsed.hostname !== "localhost" && parsed.hostname !== "127.0.0.1") {
34
+ throw new Error("AuthAgents: baseUrl must use HTTPS (http://localhost allowed for development)");
35
+ }
36
+ } catch (e) {
37
+ if (e instanceof Error && e.message.startsWith("AuthAgents:")) throw e;
38
+ throw new Error("AuthAgents: baseUrl must be a valid URL");
39
+ }
40
+ this.baseUrl = url;
31
41
  }
32
42
  // ---- Static Crypto Helpers ---------------------------------------------
33
43
  /**
@@ -72,6 +82,12 @@ var AuthAgents = class {
72
82
  * @returns base64url-encoded Ed25519 signature
73
83
  */
74
84
  static async signChallenge(privateKeyJwk, nonce) {
85
+ if (!privateKeyJwk?.d) {
86
+ throw new Error("privateKeyJwk must contain the 'd' (private key) parameter");
87
+ }
88
+ if (!nonce) {
89
+ throw new Error("nonce must not be empty");
90
+ }
75
91
  const key = await crypto.subtle.importKey(
76
92
  "jwk",
77
93
  { ...privateKeyJwk, key_ops: ["sign"] },
@@ -94,15 +110,28 @@ var AuthAgents = class {
94
110
  * Verify a VC-JWT credential issued by Agent Auth.
95
111
  *
96
112
  * @param credential - The VC-JWT string from the agent
97
- * @returns Verified agent identity or error details
113
+ * @returns Verified agent identity. If API returns 401, returns
114
+ * `{ valid: false, error, message }` instead of throwing.
98
115
  */
99
116
  async verify(credential) {
100
117
  const res = await fetch(`${this.baseUrl}/v1/credentials/verify`, {
101
118
  method: "POST",
102
119
  headers: { "Content-Type": "application/json" },
103
- body: JSON.stringify({ credential })
120
+ body: JSON.stringify({ credential }),
121
+ signal: AbortSignal.timeout(1e4)
104
122
  });
105
- return res.json();
123
+ const body = await res.json().catch(() => ({}));
124
+ if (res.status === 401) {
125
+ return {
126
+ valid: false,
127
+ error: body.error ?? "signature_invalid",
128
+ message: body.message ?? "Credential verification failed"
129
+ };
130
+ }
131
+ if (!res.ok) {
132
+ throw new Error(body.error ?? body.message ?? `Verify failed (${res.status})`);
133
+ }
134
+ return body;
106
135
  }
107
136
  // ---- Agent Registration ------------------------------------------------
108
137
  /**
@@ -117,12 +146,13 @@ var AuthAgents = class {
117
146
  const res = await fetch(`${this.baseUrl}/v1/identities`, {
118
147
  method: "POST",
119
148
  headers: { "Content-Type": "application/json" },
120
- body: JSON.stringify(input)
149
+ body: JSON.stringify(input),
150
+ signal: AbortSignal.timeout(1e4)
121
151
  });
122
152
  if (!res.ok) {
123
153
  const body = await res.json().catch(() => ({}));
124
154
  throw new Error(
125
- body.error ?? `Registration failed (${res.status})`
155
+ body.error_description ?? body.error ?? `Registration failed (${res.status})`
126
156
  );
127
157
  }
128
158
  return res.json();
@@ -132,18 +162,24 @@ var AuthAgents = class {
132
162
  * Request an authentication challenge nonce.
133
163
  *
134
164
  * @param did - The agent's DID
165
+ * @param site_id - Optional site scope for provisioned deployments
166
+ * @param credential_expires_in - Optional credential lifetime in seconds (set by website developer). Use 0 for non-expiring. Min 300, max 2592000.
135
167
  * @returns Challenge ID and nonce to sign
136
168
  */
137
- async challenge(did) {
169
+ async challenge(did, site_id, credential_expires_in) {
170
+ const payload = { did };
171
+ if (site_id) payload.site_id = site_id;
172
+ if (credential_expires_in !== void 0) payload.credential_expires_in = credential_expires_in;
138
173
  const res = await fetch(`${this.baseUrl}/v1/auth/challenge`, {
139
174
  method: "POST",
140
175
  headers: { "Content-Type": "application/json" },
141
- body: JSON.stringify({ did })
176
+ body: JSON.stringify(payload),
177
+ signal: AbortSignal.timeout(1e4)
142
178
  });
143
179
  if (!res.ok) {
144
180
  const body = await res.json().catch(() => ({}));
145
181
  throw new Error(
146
- body.error ?? `Challenge failed (${res.status})`
182
+ body.error_description ?? body.error ?? `Challenge failed (${res.status})`
147
183
  );
148
184
  }
149
185
  return res.json();
@@ -152,15 +188,28 @@ var AuthAgents = class {
152
188
  * Submit a signed challenge to authenticate and receive a fresh credential.
153
189
  *
154
190
  * @param input - challenge_id, did, and base64url signature
155
- * @returns Session token and fresh VC-JWT credential
191
+ * @returns Session token and fresh VC-JWT credential. If API returns 401,
192
+ * returns `{ valid: false, error, message }` instead of throwing.
156
193
  */
157
194
  async authenticate(input) {
158
195
  const res = await fetch(`${this.baseUrl}/v1/auth/verify`, {
159
196
  method: "POST",
160
197
  headers: { "Content-Type": "application/json" },
161
- body: JSON.stringify(input)
198
+ body: JSON.stringify(input),
199
+ signal: AbortSignal.timeout(1e4)
162
200
  });
163
- return res.json();
201
+ const body = await res.json().catch(() => ({}));
202
+ if (res.status === 401) {
203
+ return {
204
+ valid: false,
205
+ error: body.error ?? "signature_invalid",
206
+ message: body.message ?? "Authentication failed"
207
+ };
208
+ }
209
+ if (!res.ok) {
210
+ throw new Error(body.error ?? body.message ?? `Authentication failed (${res.status})`);
211
+ }
212
+ return body;
164
213
  }
165
214
  };
166
215
  async function verify(credential) {
package/dist/index.mjs CHANGED
@@ -1,8 +1,18 @@
1
1
  // src/index.ts
2
- var DEFAULT_BASE_URL = "https://auth.getagentauth.com";
2
+ var DEFAULT_BASE_URL = "https://auth.usevigil.dev";
3
3
  var AuthAgents = class {
4
4
  constructor(config) {
5
- this.baseUrl = (config?.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
5
+ const url = (config?.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
6
+ try {
7
+ const parsed = new URL(url);
8
+ if (parsed.protocol !== "https:" && parsed.hostname !== "localhost" && parsed.hostname !== "127.0.0.1") {
9
+ throw new Error("AuthAgents: baseUrl must use HTTPS (http://localhost allowed for development)");
10
+ }
11
+ } catch (e) {
12
+ if (e instanceof Error && e.message.startsWith("AuthAgents:")) throw e;
13
+ throw new Error("AuthAgents: baseUrl must be a valid URL");
14
+ }
15
+ this.baseUrl = url;
6
16
  }
7
17
  // ---- Static Crypto Helpers ---------------------------------------------
8
18
  /**
@@ -47,6 +57,12 @@ var AuthAgents = class {
47
57
  * @returns base64url-encoded Ed25519 signature
48
58
  */
49
59
  static async signChallenge(privateKeyJwk, nonce) {
60
+ if (!privateKeyJwk?.d) {
61
+ throw new Error("privateKeyJwk must contain the 'd' (private key) parameter");
62
+ }
63
+ if (!nonce) {
64
+ throw new Error("nonce must not be empty");
65
+ }
50
66
  const key = await crypto.subtle.importKey(
51
67
  "jwk",
52
68
  { ...privateKeyJwk, key_ops: ["sign"] },
@@ -69,15 +85,28 @@ var AuthAgents = class {
69
85
  * Verify a VC-JWT credential issued by Agent Auth.
70
86
  *
71
87
  * @param credential - The VC-JWT string from the agent
72
- * @returns Verified agent identity or error details
88
+ * @returns Verified agent identity. If API returns 401, returns
89
+ * `{ valid: false, error, message }` instead of throwing.
73
90
  */
74
91
  async verify(credential) {
75
92
  const res = await fetch(`${this.baseUrl}/v1/credentials/verify`, {
76
93
  method: "POST",
77
94
  headers: { "Content-Type": "application/json" },
78
- body: JSON.stringify({ credential })
95
+ body: JSON.stringify({ credential }),
96
+ signal: AbortSignal.timeout(1e4)
79
97
  });
80
- return res.json();
98
+ const body = await res.json().catch(() => ({}));
99
+ if (res.status === 401) {
100
+ return {
101
+ valid: false,
102
+ error: body.error ?? "signature_invalid",
103
+ message: body.message ?? "Credential verification failed"
104
+ };
105
+ }
106
+ if (!res.ok) {
107
+ throw new Error(body.error ?? body.message ?? `Verify failed (${res.status})`);
108
+ }
109
+ return body;
81
110
  }
82
111
  // ---- Agent Registration ------------------------------------------------
83
112
  /**
@@ -92,12 +121,13 @@ var AuthAgents = class {
92
121
  const res = await fetch(`${this.baseUrl}/v1/identities`, {
93
122
  method: "POST",
94
123
  headers: { "Content-Type": "application/json" },
95
- body: JSON.stringify(input)
124
+ body: JSON.stringify(input),
125
+ signal: AbortSignal.timeout(1e4)
96
126
  });
97
127
  if (!res.ok) {
98
128
  const body = await res.json().catch(() => ({}));
99
129
  throw new Error(
100
- body.error ?? `Registration failed (${res.status})`
130
+ body.error_description ?? body.error ?? `Registration failed (${res.status})`
101
131
  );
102
132
  }
103
133
  return res.json();
@@ -107,18 +137,24 @@ var AuthAgents = class {
107
137
  * Request an authentication challenge nonce.
108
138
  *
109
139
  * @param did - The agent's DID
140
+ * @param site_id - Optional site scope for provisioned deployments
141
+ * @param credential_expires_in - Optional credential lifetime in seconds (set by website developer). Use 0 for non-expiring. Min 300, max 2592000.
110
142
  * @returns Challenge ID and nonce to sign
111
143
  */
112
- async challenge(did) {
144
+ async challenge(did, site_id, credential_expires_in) {
145
+ const payload = { did };
146
+ if (site_id) payload.site_id = site_id;
147
+ if (credential_expires_in !== void 0) payload.credential_expires_in = credential_expires_in;
113
148
  const res = await fetch(`${this.baseUrl}/v1/auth/challenge`, {
114
149
  method: "POST",
115
150
  headers: { "Content-Type": "application/json" },
116
- body: JSON.stringify({ did })
151
+ body: JSON.stringify(payload),
152
+ signal: AbortSignal.timeout(1e4)
117
153
  });
118
154
  if (!res.ok) {
119
155
  const body = await res.json().catch(() => ({}));
120
156
  throw new Error(
121
- body.error ?? `Challenge failed (${res.status})`
157
+ body.error_description ?? body.error ?? `Challenge failed (${res.status})`
122
158
  );
123
159
  }
124
160
  return res.json();
@@ -127,15 +163,28 @@ var AuthAgents = class {
127
163
  * Submit a signed challenge to authenticate and receive a fresh credential.
128
164
  *
129
165
  * @param input - challenge_id, did, and base64url signature
130
- * @returns Session token and fresh VC-JWT credential
166
+ * @returns Session token and fresh VC-JWT credential. If API returns 401,
167
+ * returns `{ valid: false, error, message }` instead of throwing.
131
168
  */
132
169
  async authenticate(input) {
133
170
  const res = await fetch(`${this.baseUrl}/v1/auth/verify`, {
134
171
  method: "POST",
135
172
  headers: { "Content-Type": "application/json" },
136
- body: JSON.stringify(input)
173
+ body: JSON.stringify(input),
174
+ signal: AbortSignal.timeout(1e4)
137
175
  });
138
- return res.json();
176
+ const body = await res.json().catch(() => ({}));
177
+ if (res.status === 401) {
178
+ return {
179
+ valid: false,
180
+ error: body.error ?? "signature_invalid",
181
+ message: body.message ?? "Authentication failed"
182
+ };
183
+ }
184
+ if (!res.ok) {
185
+ throw new Error(body.error ?? body.message ?? `Authentication failed (${res.status})`);
186
+ }
187
+ return body;
139
188
  }
140
189
  };
141
190
  async function verify(credential) {
package/package.json CHANGED
@@ -1,46 +1,46 @@
1
- {
2
- "name": "auth-agents",
3
- "version": "0.4.0",
4
- "description": "Verify AI agent identities with Agent Auth. DID-based authentication using Ed25519 and Verifiable Credentials.",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "exports": {
8
- ".": {
9
- "types": "./dist/index.d.ts",
10
- "import": "./dist/index.mjs",
11
- "require": "./dist/index.js"
12
- }
13
- },
14
- "files": [
15
- "dist",
16
- "README.md",
17
- "LICENSE"
18
- ],
19
- "scripts": {
20
- "build": "tsup src/index.ts --format cjs,esm --dts --clean",
21
- "prepublishOnly": "npm run build"
22
- },
23
- "keywords": [
24
- "agent-auth",
25
- "getagentauth",
26
- "auth-agents",
27
- "ai-agent",
28
- "did",
29
- "verifiable-credential",
30
- "ed25519",
31
- "authentication",
32
- "identity",
33
- "decentralized-identity"
34
- ],
35
- "author": "Zeliang Cheng",
36
- "license": "MIT",
37
- "repository": {
38
- "type": "git",
39
- "url": "https://github.com/AgenthAgent/auth-agents-sdk-node"
40
- },
41
- "homepage": "https://getagentauth.com",
42
- "devDependencies": {
43
- "tsup": "^8.0.0",
44
- "typescript": "^5.0.0"
45
- }
46
- }
1
+ {
2
+ "name": "auth-agents",
3
+ "version": "0.4.3",
4
+ "description": "Verify AI agent identities with Agent Auth. DID-based authentication using Ed25519 and Verifiable Credentials.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
21
+ "prepublishOnly": "npm run build"
22
+ },
23
+ "keywords": [
24
+ "agent-auth",
25
+ "usevigil",
26
+ "auth-agents",
27
+ "ai-agent",
28
+ "did",
29
+ "verifiable-credential",
30
+ "ed25519",
31
+ "authentication",
32
+ "identity",
33
+ "decentralized-identity"
34
+ ],
35
+ "author": "Zeliang Cheng",
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/AgenthAgent/auth-agents-sdk-node"
40
+ },
41
+ "homepage": "https://usevigil.dev",
42
+ "devDependencies": {
43
+ "tsup": "^8.0.0",
44
+ "typescript": "^5.0.0"
45
+ }
46
+ }