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 +21 -21
- package/README.md +264 -243
- package/dist/index.d.mts +10 -5
- package/dist/index.d.ts +10 -5
- package/dist/index.js +62 -13
- package/dist/index.mjs +62 -13
- package/package.json +46 -46
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://
|
|
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.
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
|
|
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.
|
|
261
|
+
### `client.challenge(did, site_id?, credential_expires_in?)` — Request an auth challenge
|
|
250
262
|
|
|
251
|
-
|
|
263
|
+
`site_id` is optional and scopes the challenge/session when your deployment uses site-level org provisioning.
|
|
252
264
|
|
|
253
|
-
|
|
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
|
-
|
|
267
|
+
### `client.authenticate(input)` — Submit signed challenge
|
|
256
268
|
|
|
257
|
-
|
|
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.
|
|
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
|
|
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.
|
|
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
|
|
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.
|
|
27
|
+
var DEFAULT_BASE_URL = "https://auth.usevigil.dev";
|
|
28
28
|
var AuthAgents = class {
|
|
29
29
|
constructor(config) {
|
|
30
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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.
|
|
2
|
+
var DEFAULT_BASE_URL = "https://auth.usevigil.dev";
|
|
3
3
|
var AuthAgents = class {
|
|
4
4
|
constructor(config) {
|
|
5
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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.
|
|
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
|
-
"
|
|
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://
|
|
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
|
+
}
|