auth-agents 0.1.3 → 0.4.2
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 +165 -29
- package/dist/index.d.mts +59 -11
- package/dist/index.d.ts +59 -11
- package/dist/index.js +122 -16
- package/dist/index.mjs +122 -16
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# auth-agents
|
|
2
2
|
|
|
3
|
-
Verify AI agent identities with [Agent Auth](https://
|
|
3
|
+
Verify AI agent identities with [Agent Auth](https://usevigil.dev). DID-based authentication using Ed25519 and Verifiable Credentials.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -23,14 +23,110 @@ if (result.valid) {
|
|
|
23
23
|
console.log(result.agent_model) // "claude-opus-4-6"
|
|
24
24
|
console.log(result.agent_provider) // "Anthropic"
|
|
25
25
|
console.log(result.agent_purpose) // "Research assistant"
|
|
26
|
+
console.log(result.key_origin) // "server_generated" | "client_provided"
|
|
26
27
|
console.log(result.expires_at) // "2026-02-27T01:58:15.000Z"
|
|
27
28
|
}
|
|
28
29
|
```
|
|
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
|
+
|
|
30
126
|
## Website Integration (Next.js)
|
|
31
127
|
|
|
32
128
|
```typescript
|
|
33
|
-
// app/api/auth/agent/route.ts
|
|
129
|
+
// app/api/auth/agent-login/route.ts
|
|
34
130
|
import { AuthAgents } from "auth-agents"
|
|
35
131
|
|
|
36
132
|
const authAgents = new AuthAgents()
|
|
@@ -51,6 +147,7 @@ export async function POST(request: Request) {
|
|
|
51
147
|
did: result.did,
|
|
52
148
|
agent_name: result.agent_name,
|
|
53
149
|
agent_model: result.agent_model,
|
|
150
|
+
key_origin: result.key_origin,
|
|
54
151
|
expires_at: result.expires_at,
|
|
55
152
|
})
|
|
56
153
|
|
|
@@ -67,7 +164,7 @@ import { AuthAgents } from "auth-agents"
|
|
|
67
164
|
const app = express()
|
|
68
165
|
const authAgents = new AuthAgents()
|
|
69
166
|
|
|
70
|
-
app.post("/auth/agent", express.json(), async (req, res) => {
|
|
167
|
+
app.post("/auth/agent-login", express.json(), async (req, res) => {
|
|
71
168
|
const { credential } = req.body
|
|
72
169
|
const result = await authAgents.verify(credential)
|
|
73
170
|
|
|
@@ -80,57 +177,96 @@ app.post("/auth/agent", express.json(), async (req, res) => {
|
|
|
80
177
|
did: result.did,
|
|
81
178
|
name: result.agent_name,
|
|
82
179
|
model: result.agent_model,
|
|
180
|
+
key_origin: result.key_origin,
|
|
83
181
|
}
|
|
84
182
|
|
|
85
183
|
res.json({ authenticated: true, agent_name: result.agent_name })
|
|
86
184
|
})
|
|
87
185
|
```
|
|
88
186
|
|
|
89
|
-
##
|
|
187
|
+
## API
|
|
90
188
|
|
|
91
|
-
|
|
92
|
-
import { AuthAgents } from "auth-agents"
|
|
189
|
+
### `new AuthAgents(config?)`
|
|
93
190
|
|
|
94
|
-
|
|
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.
|
|
95
192
|
|
|
96
|
-
|
|
97
|
-
const identity = await client.register({
|
|
98
|
-
agent_name: "Claude",
|
|
99
|
-
agent_model: "claude-opus-4-6",
|
|
100
|
-
agent_provider: "Anthropic",
|
|
101
|
-
agent_purpose: "Research assistant",
|
|
102
|
-
})
|
|
193
|
+
### `AuthAgents.generateKeyPair()` — Static
|
|
103
194
|
|
|
104
|
-
|
|
105
|
-
const challenge = await client.challenge(identity.did)
|
|
195
|
+
Generate a local Ed25519 key pair using the Web Crypto API. No network call.
|
|
106
196
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
// auth.credential — fresh VC-JWT
|
|
114
|
-
// auth.session_token — session ID
|
|
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
|
+
}
|
|
115
203
|
```
|
|
116
204
|
|
|
117
|
-
|
|
205
|
+
### `AuthAgents.signChallenge(privateKeyJwk, nonce)` — Static
|
|
118
206
|
|
|
119
|
-
|
|
207
|
+
Sign an authentication challenge nonce with an Ed25519 private key. No network call.
|
|
120
208
|
|
|
121
|
-
- `
|
|
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.
|
|
122
213
|
|
|
123
214
|
### `client.verify(credential)` — Verify a VC-JWT credential
|
|
124
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
|
+
|
|
125
241
|
### `client.register(input)` — Register a new agent identity
|
|
126
242
|
|
|
127
|
-
|
|
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
|
+
- `credential_expires_in` — credential lifetime in seconds (`0` means non-expiring)
|
|
246
|
+
- `metadata` — key/value metadata map (max key/value sizes enforced server-side)
|
|
247
|
+
|
|
248
|
+
Returns `RegisterResult`:
|
|
249
|
+
```typescript
|
|
250
|
+
{
|
|
251
|
+
did: string
|
|
252
|
+
credential: string
|
|
253
|
+
key_fingerprint: string
|
|
254
|
+
key_origin?: "server_generated" | "client_provided"
|
|
255
|
+
private_key_jwk?: { kty, crv, x, d } // only present for server_generated
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### `client.challenge(did, site_id?)` — Request an auth challenge
|
|
260
|
+
|
|
261
|
+
`site_id` is optional and scopes the challenge/session when your deployment uses site-level org provisioning.
|
|
128
262
|
|
|
129
263
|
### `client.authenticate(input)` — Submit signed challenge
|
|
130
264
|
|
|
265
|
+
`input` supports optional `credential_expires_in` to customize the issued credential lifetime (`0` means non-expiring).
|
|
266
|
+
|
|
131
267
|
## Documentation
|
|
132
268
|
|
|
133
|
-
Full API reference at [
|
|
269
|
+
Full API reference at [usevigil.dev/docs](https://usevigil.dev/docs/)
|
|
134
270
|
|
|
135
271
|
## License
|
|
136
272
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
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
|
+
/** Ed25519 key pair in JWK format, returned by generateKeyPair() */
|
|
6
|
+
interface Ed25519KeyPair {
|
|
7
|
+
publicKeyJwk: {
|
|
8
|
+
kty: string;
|
|
9
|
+
crv: string;
|
|
10
|
+
x: string;
|
|
11
|
+
};
|
|
12
|
+
privateKeyJwk: {
|
|
13
|
+
kty: string;
|
|
14
|
+
crv: string;
|
|
15
|
+
x: string;
|
|
16
|
+
d: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
5
19
|
interface VerifyResult {
|
|
6
20
|
valid: true;
|
|
7
21
|
did: string;
|
|
@@ -12,10 +26,11 @@ interface VerifyResult {
|
|
|
12
26
|
key_fingerprint: string | null;
|
|
13
27
|
issued_at: string | null;
|
|
14
28
|
expires_at: string | null;
|
|
29
|
+
key_origin: string | null;
|
|
15
30
|
}
|
|
16
31
|
interface VerifyError {
|
|
17
32
|
valid: false;
|
|
18
|
-
error: "credential_expired" | "invalid_issuer" | "signature_invalid";
|
|
33
|
+
error: "credential_expired" | "invalid_issuer" | "signature_invalid" | "credential_revoked";
|
|
19
34
|
message: string;
|
|
20
35
|
}
|
|
21
36
|
type VerifyResponse = VerifyResult | VerifyError;
|
|
@@ -29,11 +44,14 @@ interface RegisterInput {
|
|
|
29
44
|
crv: string;
|
|
30
45
|
x: string;
|
|
31
46
|
};
|
|
47
|
+
credential_expires_in?: number;
|
|
48
|
+
metadata?: Record<string, string>;
|
|
32
49
|
}
|
|
33
50
|
interface RegisterResult {
|
|
34
51
|
did: string;
|
|
35
52
|
credential: string;
|
|
36
53
|
key_fingerprint: string;
|
|
54
|
+
key_origin?: "server_generated" | "client_provided";
|
|
37
55
|
private_key_jwk?: {
|
|
38
56
|
kty: string;
|
|
39
57
|
crv: string;
|
|
@@ -51,6 +69,7 @@ interface AuthVerifyInput {
|
|
|
51
69
|
challenge_id: string;
|
|
52
70
|
did: string;
|
|
53
71
|
signature: string;
|
|
72
|
+
credential_expires_in?: number;
|
|
54
73
|
}
|
|
55
74
|
interface AuthVerifyResult {
|
|
56
75
|
valid: true;
|
|
@@ -75,33 +94,62 @@ type AuthVerifyResponse = AuthVerifyResult | AuthVerifyError;
|
|
|
75
94
|
declare class AuthAgents {
|
|
76
95
|
private baseUrl;
|
|
77
96
|
constructor(config?: AuthAgentsConfig);
|
|
97
|
+
/**
|
|
98
|
+
* Generate an Ed25519 key pair using the Web Crypto API.
|
|
99
|
+
* Use the returned public key JWK for BYOK registration and the private key
|
|
100
|
+
* JWK with signChallenge() to complete headless authentication.
|
|
101
|
+
*
|
|
102
|
+
* SECURITY: Store the private key securely. Never transmit it over the wire.
|
|
103
|
+
*
|
|
104
|
+
* @returns Ed25519 key pair in JWK format
|
|
105
|
+
*/
|
|
106
|
+
static generateKeyPair(): Promise<Ed25519KeyPair>;
|
|
107
|
+
/**
|
|
108
|
+
* Sign an authentication challenge nonce with an Ed25519 private key.
|
|
109
|
+
* The nonce is signed as UTF-8 encoded text (NOT hex-decoded bytes).
|
|
110
|
+
* Returns a base64url-encoded signature string.
|
|
111
|
+
*
|
|
112
|
+
* @param privateKeyJwk - The agent's private key in JWK format (must include `d`)
|
|
113
|
+
* @param nonce - The challenge nonce string returned by client.challenge()
|
|
114
|
+
* @returns base64url-encoded Ed25519 signature
|
|
115
|
+
*/
|
|
116
|
+
static signChallenge(privateKeyJwk: {
|
|
117
|
+
kty: string;
|
|
118
|
+
crv: string;
|
|
119
|
+
x: string;
|
|
120
|
+
d: string;
|
|
121
|
+
}, nonce: string): Promise<string>;
|
|
78
122
|
/**
|
|
79
123
|
* Verify a VC-JWT credential issued by Agent Auth.
|
|
80
124
|
*
|
|
81
125
|
* @param credential - The VC-JWT string from the agent
|
|
82
|
-
* @returns Verified agent identity
|
|
126
|
+
* @returns Verified agent identity. If API returns 401, returns
|
|
127
|
+
* `{ valid: false, error, message }` instead of throwing.
|
|
83
128
|
*/
|
|
84
129
|
verify(credential: string): Promise<VerifyResponse>;
|
|
85
130
|
/**
|
|
86
|
-
* Register a new agent identity.
|
|
87
|
-
* and returns
|
|
131
|
+
* Register a new agent identity. By default the server generates an Ed25519
|
|
132
|
+
* keypair and returns the private key. Pass `public_key_jwk` to use your own
|
|
133
|
+
* key (BYOK) — in that case no private key is returned.
|
|
88
134
|
*
|
|
89
|
-
* @param input - Agent metadata
|
|
90
|
-
* @returns DID, credential, and private key
|
|
135
|
+
* @param input - Agent metadata and optional public key JWK for BYOK
|
|
136
|
+
* @returns DID, credential, key_origin, and private key if server-generated
|
|
91
137
|
*/
|
|
92
138
|
register(input: RegisterInput): Promise<RegisterResult>;
|
|
93
139
|
/**
|
|
94
140
|
* Request an authentication challenge nonce.
|
|
95
141
|
*
|
|
96
142
|
* @param did - The agent's DID
|
|
143
|
+
* @param site_id - Optional site scope for provisioned deployments
|
|
97
144
|
* @returns Challenge ID and nonce to sign
|
|
98
145
|
*/
|
|
99
|
-
challenge(did: string): Promise<ChallengeResult>;
|
|
146
|
+
challenge(did: string, site_id?: string): Promise<ChallengeResult>;
|
|
100
147
|
/**
|
|
101
148
|
* Submit a signed challenge to authenticate and receive a fresh credential.
|
|
102
149
|
*
|
|
103
|
-
* @param input - challenge_id, did, and
|
|
104
|
-
* @returns Session token and fresh VC-JWT credential
|
|
150
|
+
* @param input - challenge_id, did, base64url signature, and optional credential_expires_in
|
|
151
|
+
* @returns Session token and fresh VC-JWT credential. If API returns 401,
|
|
152
|
+
* returns `{ valid: false, error, message }` instead of throwing.
|
|
105
153
|
*/
|
|
106
154
|
authenticate(input: AuthVerifyInput): Promise<AuthVerifyResponse>;
|
|
107
155
|
}
|
|
@@ -111,4 +159,4 @@ declare class AuthAgents {
|
|
|
111
159
|
*/
|
|
112
160
|
declare function verify(credential: string): Promise<VerifyResponse>;
|
|
113
161
|
|
|
114
|
-
export { AuthAgents, type AuthAgentsConfig, type AuthVerifyError, type AuthVerifyInput, type AuthVerifyResponse, type AuthVerifyResult, type ChallengeResult, type RegisterInput, type RegisterResult, type VerifyError, type VerifyResponse, type VerifyResult, verify };
|
|
162
|
+
export { AuthAgents, type AuthAgentsConfig, type AuthVerifyError, type AuthVerifyInput, type AuthVerifyResponse, type AuthVerifyResult, type ChallengeResult, type Ed25519KeyPair, type RegisterInput, type RegisterResult, type VerifyError, type VerifyResponse, type VerifyResult, verify };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
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
|
+
/** Ed25519 key pair in JWK format, returned by generateKeyPair() */
|
|
6
|
+
interface Ed25519KeyPair {
|
|
7
|
+
publicKeyJwk: {
|
|
8
|
+
kty: string;
|
|
9
|
+
crv: string;
|
|
10
|
+
x: string;
|
|
11
|
+
};
|
|
12
|
+
privateKeyJwk: {
|
|
13
|
+
kty: string;
|
|
14
|
+
crv: string;
|
|
15
|
+
x: string;
|
|
16
|
+
d: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
5
19
|
interface VerifyResult {
|
|
6
20
|
valid: true;
|
|
7
21
|
did: string;
|
|
@@ -12,10 +26,11 @@ interface VerifyResult {
|
|
|
12
26
|
key_fingerprint: string | null;
|
|
13
27
|
issued_at: string | null;
|
|
14
28
|
expires_at: string | null;
|
|
29
|
+
key_origin: string | null;
|
|
15
30
|
}
|
|
16
31
|
interface VerifyError {
|
|
17
32
|
valid: false;
|
|
18
|
-
error: "credential_expired" | "invalid_issuer" | "signature_invalid";
|
|
33
|
+
error: "credential_expired" | "invalid_issuer" | "signature_invalid" | "credential_revoked";
|
|
19
34
|
message: string;
|
|
20
35
|
}
|
|
21
36
|
type VerifyResponse = VerifyResult | VerifyError;
|
|
@@ -29,11 +44,14 @@ interface RegisterInput {
|
|
|
29
44
|
crv: string;
|
|
30
45
|
x: string;
|
|
31
46
|
};
|
|
47
|
+
credential_expires_in?: number;
|
|
48
|
+
metadata?: Record<string, string>;
|
|
32
49
|
}
|
|
33
50
|
interface RegisterResult {
|
|
34
51
|
did: string;
|
|
35
52
|
credential: string;
|
|
36
53
|
key_fingerprint: string;
|
|
54
|
+
key_origin?: "server_generated" | "client_provided";
|
|
37
55
|
private_key_jwk?: {
|
|
38
56
|
kty: string;
|
|
39
57
|
crv: string;
|
|
@@ -51,6 +69,7 @@ interface AuthVerifyInput {
|
|
|
51
69
|
challenge_id: string;
|
|
52
70
|
did: string;
|
|
53
71
|
signature: string;
|
|
72
|
+
credential_expires_in?: number;
|
|
54
73
|
}
|
|
55
74
|
interface AuthVerifyResult {
|
|
56
75
|
valid: true;
|
|
@@ -75,33 +94,62 @@ type AuthVerifyResponse = AuthVerifyResult | AuthVerifyError;
|
|
|
75
94
|
declare class AuthAgents {
|
|
76
95
|
private baseUrl;
|
|
77
96
|
constructor(config?: AuthAgentsConfig);
|
|
97
|
+
/**
|
|
98
|
+
* Generate an Ed25519 key pair using the Web Crypto API.
|
|
99
|
+
* Use the returned public key JWK for BYOK registration and the private key
|
|
100
|
+
* JWK with signChallenge() to complete headless authentication.
|
|
101
|
+
*
|
|
102
|
+
* SECURITY: Store the private key securely. Never transmit it over the wire.
|
|
103
|
+
*
|
|
104
|
+
* @returns Ed25519 key pair in JWK format
|
|
105
|
+
*/
|
|
106
|
+
static generateKeyPair(): Promise<Ed25519KeyPair>;
|
|
107
|
+
/**
|
|
108
|
+
* Sign an authentication challenge nonce with an Ed25519 private key.
|
|
109
|
+
* The nonce is signed as UTF-8 encoded text (NOT hex-decoded bytes).
|
|
110
|
+
* Returns a base64url-encoded signature string.
|
|
111
|
+
*
|
|
112
|
+
* @param privateKeyJwk - The agent's private key in JWK format (must include `d`)
|
|
113
|
+
* @param nonce - The challenge nonce string returned by client.challenge()
|
|
114
|
+
* @returns base64url-encoded Ed25519 signature
|
|
115
|
+
*/
|
|
116
|
+
static signChallenge(privateKeyJwk: {
|
|
117
|
+
kty: string;
|
|
118
|
+
crv: string;
|
|
119
|
+
x: string;
|
|
120
|
+
d: string;
|
|
121
|
+
}, nonce: string): Promise<string>;
|
|
78
122
|
/**
|
|
79
123
|
* Verify a VC-JWT credential issued by Agent Auth.
|
|
80
124
|
*
|
|
81
125
|
* @param credential - The VC-JWT string from the agent
|
|
82
|
-
* @returns Verified agent identity
|
|
126
|
+
* @returns Verified agent identity. If API returns 401, returns
|
|
127
|
+
* `{ valid: false, error, message }` instead of throwing.
|
|
83
128
|
*/
|
|
84
129
|
verify(credential: string): Promise<VerifyResponse>;
|
|
85
130
|
/**
|
|
86
|
-
* Register a new agent identity.
|
|
87
|
-
* and returns
|
|
131
|
+
* Register a new agent identity. By default the server generates an Ed25519
|
|
132
|
+
* keypair and returns the private key. Pass `public_key_jwk` to use your own
|
|
133
|
+
* key (BYOK) — in that case no private key is returned.
|
|
88
134
|
*
|
|
89
|
-
* @param input - Agent metadata
|
|
90
|
-
* @returns DID, credential, and private key
|
|
135
|
+
* @param input - Agent metadata and optional public key JWK for BYOK
|
|
136
|
+
* @returns DID, credential, key_origin, and private key if server-generated
|
|
91
137
|
*/
|
|
92
138
|
register(input: RegisterInput): Promise<RegisterResult>;
|
|
93
139
|
/**
|
|
94
140
|
* Request an authentication challenge nonce.
|
|
95
141
|
*
|
|
96
142
|
* @param did - The agent's DID
|
|
143
|
+
* @param site_id - Optional site scope for provisioned deployments
|
|
97
144
|
* @returns Challenge ID and nonce to sign
|
|
98
145
|
*/
|
|
99
|
-
challenge(did: string): Promise<ChallengeResult>;
|
|
146
|
+
challenge(did: string, site_id?: string): Promise<ChallengeResult>;
|
|
100
147
|
/**
|
|
101
148
|
* Submit a signed challenge to authenticate and receive a fresh credential.
|
|
102
149
|
*
|
|
103
|
-
* @param input - challenge_id, did, and
|
|
104
|
-
* @returns Session token and fresh VC-JWT credential
|
|
150
|
+
* @param input - challenge_id, did, base64url signature, and optional credential_expires_in
|
|
151
|
+
* @returns Session token and fresh VC-JWT credential. If API returns 401,
|
|
152
|
+
* returns `{ valid: false, error, message }` instead of throwing.
|
|
105
153
|
*/
|
|
106
154
|
authenticate(input: AuthVerifyInput): Promise<AuthVerifyResponse>;
|
|
107
155
|
}
|
|
@@ -111,4 +159,4 @@ declare class AuthAgents {
|
|
|
111
159
|
*/
|
|
112
160
|
declare function verify(credential: string): Promise<VerifyResponse>;
|
|
113
161
|
|
|
114
|
-
export { AuthAgents, type AuthAgentsConfig, type AuthVerifyError, type AuthVerifyInput, type AuthVerifyResponse, type AuthVerifyResult, type ChallengeResult, type RegisterInput, type RegisterResult, type VerifyError, type VerifyResponse, type VerifyResult, verify };
|
|
162
|
+
export { AuthAgents, type AuthAgentsConfig, type AuthVerifyError, type AuthVerifyInput, type AuthVerifyResponse, type AuthVerifyResult, type ChallengeResult, type Ed25519KeyPair, type RegisterInput, type RegisterResult, type VerifyError, type VerifyResponse, type VerifyResult, verify };
|
package/dist/index.js
CHANGED
|
@@ -24,39 +24,130 @@ __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;
|
|
41
|
+
}
|
|
42
|
+
// ---- Static Crypto Helpers ---------------------------------------------
|
|
43
|
+
/**
|
|
44
|
+
* Generate an Ed25519 key pair using the Web Crypto API.
|
|
45
|
+
* Use the returned public key JWK for BYOK registration and the private key
|
|
46
|
+
* JWK with signChallenge() to complete headless authentication.
|
|
47
|
+
*
|
|
48
|
+
* SECURITY: Store the private key securely. Never transmit it over the wire.
|
|
49
|
+
*
|
|
50
|
+
* @returns Ed25519 key pair in JWK format
|
|
51
|
+
*/
|
|
52
|
+
static async generateKeyPair() {
|
|
53
|
+
const keyPair = await crypto.subtle.generateKey(
|
|
54
|
+
"Ed25519",
|
|
55
|
+
true,
|
|
56
|
+
// extractable
|
|
57
|
+
["sign", "verify"]
|
|
58
|
+
);
|
|
59
|
+
const publicJwk = await crypto.subtle.exportKey("jwk", keyPair.publicKey);
|
|
60
|
+
const privateJwk = await crypto.subtle.exportKey("jwk", keyPair.privateKey);
|
|
61
|
+
return {
|
|
62
|
+
publicKeyJwk: {
|
|
63
|
+
kty: publicJwk.kty,
|
|
64
|
+
crv: publicJwk.crv,
|
|
65
|
+
x: publicJwk.x
|
|
66
|
+
},
|
|
67
|
+
privateKeyJwk: {
|
|
68
|
+
kty: privateJwk.kty,
|
|
69
|
+
crv: privateJwk.crv,
|
|
70
|
+
x: privateJwk.x,
|
|
71
|
+
d: privateJwk.d
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Sign an authentication challenge nonce with an Ed25519 private key.
|
|
77
|
+
* The nonce is signed as UTF-8 encoded text (NOT hex-decoded bytes).
|
|
78
|
+
* Returns a base64url-encoded signature string.
|
|
79
|
+
*
|
|
80
|
+
* @param privateKeyJwk - The agent's private key in JWK format (must include `d`)
|
|
81
|
+
* @param nonce - The challenge nonce string returned by client.challenge()
|
|
82
|
+
* @returns base64url-encoded Ed25519 signature
|
|
83
|
+
*/
|
|
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
|
+
}
|
|
91
|
+
const key = await crypto.subtle.importKey(
|
|
92
|
+
"jwk",
|
|
93
|
+
{ ...privateKeyJwk, key_ops: ["sign"] },
|
|
94
|
+
"Ed25519",
|
|
95
|
+
false,
|
|
96
|
+
["sign"]
|
|
97
|
+
);
|
|
98
|
+
const data = new TextEncoder().encode(nonce);
|
|
99
|
+
const signatureBuffer = await crypto.subtle.sign("Ed25519", key, data);
|
|
100
|
+
const bytes = new Uint8Array(signatureBuffer);
|
|
101
|
+
let binary = "";
|
|
102
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
103
|
+
binary += String.fromCharCode(bytes[i]);
|
|
104
|
+
}
|
|
105
|
+
const base64 = btoa(binary);
|
|
106
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
31
107
|
}
|
|
32
108
|
// ---- Credential Verification (for websites) ----------------------------
|
|
33
109
|
/**
|
|
34
110
|
* Verify a VC-JWT credential issued by Agent Auth.
|
|
35
111
|
*
|
|
36
112
|
* @param credential - The VC-JWT string from the agent
|
|
37
|
-
* @returns Verified agent identity
|
|
113
|
+
* @returns Verified agent identity. If API returns 401, returns
|
|
114
|
+
* `{ valid: false, error, message }` instead of throwing.
|
|
38
115
|
*/
|
|
39
116
|
async verify(credential) {
|
|
40
117
|
const res = await fetch(`${this.baseUrl}/v1/credentials/verify`, {
|
|
41
118
|
method: "POST",
|
|
42
119
|
headers: { "Content-Type": "application/json" },
|
|
43
|
-
body: JSON.stringify({ credential })
|
|
120
|
+
body: JSON.stringify({ credential }),
|
|
121
|
+
signal: AbortSignal.timeout(1e4)
|
|
44
122
|
});
|
|
45
|
-
|
|
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;
|
|
46
135
|
}
|
|
47
136
|
// ---- Agent Registration ------------------------------------------------
|
|
48
137
|
/**
|
|
49
|
-
* Register a new agent identity.
|
|
50
|
-
* and returns
|
|
138
|
+
* Register a new agent identity. By default the server generates an Ed25519
|
|
139
|
+
* keypair and returns the private key. Pass `public_key_jwk` to use your own
|
|
140
|
+
* key (BYOK) — in that case no private key is returned.
|
|
51
141
|
*
|
|
52
|
-
* @param input - Agent metadata
|
|
53
|
-
* @returns DID, credential, and private key
|
|
142
|
+
* @param input - Agent metadata and optional public key JWK for BYOK
|
|
143
|
+
* @returns DID, credential, key_origin, and private key if server-generated
|
|
54
144
|
*/
|
|
55
145
|
async register(input) {
|
|
56
146
|
const res = await fetch(`${this.baseUrl}/v1/identities`, {
|
|
57
147
|
method: "POST",
|
|
58
148
|
headers: { "Content-Type": "application/json" },
|
|
59
|
-
body: JSON.stringify(input)
|
|
149
|
+
body: JSON.stringify(input),
|
|
150
|
+
signal: AbortSignal.timeout(1e4)
|
|
60
151
|
});
|
|
61
152
|
if (!res.ok) {
|
|
62
153
|
const body = await res.json().catch(() => ({}));
|
|
@@ -71,13 +162,15 @@ var AuthAgents = class {
|
|
|
71
162
|
* Request an authentication challenge nonce.
|
|
72
163
|
*
|
|
73
164
|
* @param did - The agent's DID
|
|
165
|
+
* @param site_id - Optional site scope for provisioned deployments
|
|
74
166
|
* @returns Challenge ID and nonce to sign
|
|
75
167
|
*/
|
|
76
|
-
async challenge(did) {
|
|
168
|
+
async challenge(did, site_id) {
|
|
77
169
|
const res = await fetch(`${this.baseUrl}/v1/auth/challenge`, {
|
|
78
170
|
method: "POST",
|
|
79
171
|
headers: { "Content-Type": "application/json" },
|
|
80
|
-
body: JSON.stringify({ did })
|
|
172
|
+
body: JSON.stringify(site_id ? { did, site_id } : { did }),
|
|
173
|
+
signal: AbortSignal.timeout(1e4)
|
|
81
174
|
});
|
|
82
175
|
if (!res.ok) {
|
|
83
176
|
const body = await res.json().catch(() => ({}));
|
|
@@ -90,16 +183,29 @@ var AuthAgents = class {
|
|
|
90
183
|
/**
|
|
91
184
|
* Submit a signed challenge to authenticate and receive a fresh credential.
|
|
92
185
|
*
|
|
93
|
-
* @param input - challenge_id, did, and
|
|
94
|
-
* @returns Session token and fresh VC-JWT credential
|
|
186
|
+
* @param input - challenge_id, did, base64url signature, and optional credential_expires_in
|
|
187
|
+
* @returns Session token and fresh VC-JWT credential. If API returns 401,
|
|
188
|
+
* returns `{ valid: false, error, message }` instead of throwing.
|
|
95
189
|
*/
|
|
96
190
|
async authenticate(input) {
|
|
97
191
|
const res = await fetch(`${this.baseUrl}/v1/auth/verify`, {
|
|
98
192
|
method: "POST",
|
|
99
193
|
headers: { "Content-Type": "application/json" },
|
|
100
|
-
body: JSON.stringify(input)
|
|
194
|
+
body: JSON.stringify(input),
|
|
195
|
+
signal: AbortSignal.timeout(1e4)
|
|
101
196
|
});
|
|
102
|
-
|
|
197
|
+
const body = await res.json().catch(() => ({}));
|
|
198
|
+
if (res.status === 401) {
|
|
199
|
+
return {
|
|
200
|
+
valid: false,
|
|
201
|
+
error: body.error ?? "signature_invalid",
|
|
202
|
+
message: body.message ?? "Authentication failed"
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
if (!res.ok) {
|
|
206
|
+
throw new Error(body.error ?? body.message ?? `Authentication failed (${res.status})`);
|
|
207
|
+
}
|
|
208
|
+
return body;
|
|
103
209
|
}
|
|
104
210
|
};
|
|
105
211
|
async function verify(credential) {
|
package/dist/index.mjs
CHANGED
|
@@ -1,37 +1,128 @@
|
|
|
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;
|
|
16
|
+
}
|
|
17
|
+
// ---- Static Crypto Helpers ---------------------------------------------
|
|
18
|
+
/**
|
|
19
|
+
* Generate an Ed25519 key pair using the Web Crypto API.
|
|
20
|
+
* Use the returned public key JWK for BYOK registration and the private key
|
|
21
|
+
* JWK with signChallenge() to complete headless authentication.
|
|
22
|
+
*
|
|
23
|
+
* SECURITY: Store the private key securely. Never transmit it over the wire.
|
|
24
|
+
*
|
|
25
|
+
* @returns Ed25519 key pair in JWK format
|
|
26
|
+
*/
|
|
27
|
+
static async generateKeyPair() {
|
|
28
|
+
const keyPair = await crypto.subtle.generateKey(
|
|
29
|
+
"Ed25519",
|
|
30
|
+
true,
|
|
31
|
+
// extractable
|
|
32
|
+
["sign", "verify"]
|
|
33
|
+
);
|
|
34
|
+
const publicJwk = await crypto.subtle.exportKey("jwk", keyPair.publicKey);
|
|
35
|
+
const privateJwk = await crypto.subtle.exportKey("jwk", keyPair.privateKey);
|
|
36
|
+
return {
|
|
37
|
+
publicKeyJwk: {
|
|
38
|
+
kty: publicJwk.kty,
|
|
39
|
+
crv: publicJwk.crv,
|
|
40
|
+
x: publicJwk.x
|
|
41
|
+
},
|
|
42
|
+
privateKeyJwk: {
|
|
43
|
+
kty: privateJwk.kty,
|
|
44
|
+
crv: privateJwk.crv,
|
|
45
|
+
x: privateJwk.x,
|
|
46
|
+
d: privateJwk.d
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Sign an authentication challenge nonce with an Ed25519 private key.
|
|
52
|
+
* The nonce is signed as UTF-8 encoded text (NOT hex-decoded bytes).
|
|
53
|
+
* Returns a base64url-encoded signature string.
|
|
54
|
+
*
|
|
55
|
+
* @param privateKeyJwk - The agent's private key in JWK format (must include `d`)
|
|
56
|
+
* @param nonce - The challenge nonce string returned by client.challenge()
|
|
57
|
+
* @returns base64url-encoded Ed25519 signature
|
|
58
|
+
*/
|
|
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
|
+
}
|
|
66
|
+
const key = await crypto.subtle.importKey(
|
|
67
|
+
"jwk",
|
|
68
|
+
{ ...privateKeyJwk, key_ops: ["sign"] },
|
|
69
|
+
"Ed25519",
|
|
70
|
+
false,
|
|
71
|
+
["sign"]
|
|
72
|
+
);
|
|
73
|
+
const data = new TextEncoder().encode(nonce);
|
|
74
|
+
const signatureBuffer = await crypto.subtle.sign("Ed25519", key, data);
|
|
75
|
+
const bytes = new Uint8Array(signatureBuffer);
|
|
76
|
+
let binary = "";
|
|
77
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
78
|
+
binary += String.fromCharCode(bytes[i]);
|
|
79
|
+
}
|
|
80
|
+
const base64 = btoa(binary);
|
|
81
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
6
82
|
}
|
|
7
83
|
// ---- Credential Verification (for websites) ----------------------------
|
|
8
84
|
/**
|
|
9
85
|
* Verify a VC-JWT credential issued by Agent Auth.
|
|
10
86
|
*
|
|
11
87
|
* @param credential - The VC-JWT string from the agent
|
|
12
|
-
* @returns Verified agent identity
|
|
88
|
+
* @returns Verified agent identity. If API returns 401, returns
|
|
89
|
+
* `{ valid: false, error, message }` instead of throwing.
|
|
13
90
|
*/
|
|
14
91
|
async verify(credential) {
|
|
15
92
|
const res = await fetch(`${this.baseUrl}/v1/credentials/verify`, {
|
|
16
93
|
method: "POST",
|
|
17
94
|
headers: { "Content-Type": "application/json" },
|
|
18
|
-
body: JSON.stringify({ credential })
|
|
95
|
+
body: JSON.stringify({ credential }),
|
|
96
|
+
signal: AbortSignal.timeout(1e4)
|
|
19
97
|
});
|
|
20
|
-
|
|
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;
|
|
21
110
|
}
|
|
22
111
|
// ---- Agent Registration ------------------------------------------------
|
|
23
112
|
/**
|
|
24
|
-
* Register a new agent identity.
|
|
25
|
-
* and returns
|
|
113
|
+
* Register a new agent identity. By default the server generates an Ed25519
|
|
114
|
+
* keypair and returns the private key. Pass `public_key_jwk` to use your own
|
|
115
|
+
* key (BYOK) — in that case no private key is returned.
|
|
26
116
|
*
|
|
27
|
-
* @param input - Agent metadata
|
|
28
|
-
* @returns DID, credential, and private key
|
|
117
|
+
* @param input - Agent metadata and optional public key JWK for BYOK
|
|
118
|
+
* @returns DID, credential, key_origin, and private key if server-generated
|
|
29
119
|
*/
|
|
30
120
|
async register(input) {
|
|
31
121
|
const res = await fetch(`${this.baseUrl}/v1/identities`, {
|
|
32
122
|
method: "POST",
|
|
33
123
|
headers: { "Content-Type": "application/json" },
|
|
34
|
-
body: JSON.stringify(input)
|
|
124
|
+
body: JSON.stringify(input),
|
|
125
|
+
signal: AbortSignal.timeout(1e4)
|
|
35
126
|
});
|
|
36
127
|
if (!res.ok) {
|
|
37
128
|
const body = await res.json().catch(() => ({}));
|
|
@@ -46,13 +137,15 @@ var AuthAgents = class {
|
|
|
46
137
|
* Request an authentication challenge nonce.
|
|
47
138
|
*
|
|
48
139
|
* @param did - The agent's DID
|
|
140
|
+
* @param site_id - Optional site scope for provisioned deployments
|
|
49
141
|
* @returns Challenge ID and nonce to sign
|
|
50
142
|
*/
|
|
51
|
-
async challenge(did) {
|
|
143
|
+
async challenge(did, site_id) {
|
|
52
144
|
const res = await fetch(`${this.baseUrl}/v1/auth/challenge`, {
|
|
53
145
|
method: "POST",
|
|
54
146
|
headers: { "Content-Type": "application/json" },
|
|
55
|
-
body: JSON.stringify({ did })
|
|
147
|
+
body: JSON.stringify(site_id ? { did, site_id } : { did }),
|
|
148
|
+
signal: AbortSignal.timeout(1e4)
|
|
56
149
|
});
|
|
57
150
|
if (!res.ok) {
|
|
58
151
|
const body = await res.json().catch(() => ({}));
|
|
@@ -65,16 +158,29 @@ var AuthAgents = class {
|
|
|
65
158
|
/**
|
|
66
159
|
* Submit a signed challenge to authenticate and receive a fresh credential.
|
|
67
160
|
*
|
|
68
|
-
* @param input - challenge_id, did, and
|
|
69
|
-
* @returns Session token and fresh VC-JWT credential
|
|
161
|
+
* @param input - challenge_id, did, base64url signature, and optional credential_expires_in
|
|
162
|
+
* @returns Session token and fresh VC-JWT credential. If API returns 401,
|
|
163
|
+
* returns `{ valid: false, error, message }` instead of throwing.
|
|
70
164
|
*/
|
|
71
165
|
async authenticate(input) {
|
|
72
166
|
const res = await fetch(`${this.baseUrl}/v1/auth/verify`, {
|
|
73
167
|
method: "POST",
|
|
74
168
|
headers: { "Content-Type": "application/json" },
|
|
75
|
-
body: JSON.stringify(input)
|
|
169
|
+
body: JSON.stringify(input),
|
|
170
|
+
signal: AbortSignal.timeout(1e4)
|
|
76
171
|
});
|
|
77
|
-
|
|
172
|
+
const body = await res.json().catch(() => ({}));
|
|
173
|
+
if (res.status === 401) {
|
|
174
|
+
return {
|
|
175
|
+
valid: false,
|
|
176
|
+
error: body.error ?? "signature_invalid",
|
|
177
|
+
message: body.message ?? "Authentication failed"
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
if (!res.ok) {
|
|
181
|
+
throw new Error(body.error ?? body.message ?? `Authentication failed (${res.status})`);
|
|
182
|
+
}
|
|
183
|
+
return body;
|
|
78
184
|
}
|
|
79
185
|
};
|
|
80
186
|
async function verify(credential) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "auth-agents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Verify AI agent identities with Agent Auth. DID-based authentication using Ed25519 and Verifiable Credentials.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"keywords": [
|
|
24
24
|
"agent-auth",
|
|
25
|
-
"
|
|
25
|
+
"usevigil",
|
|
26
26
|
"auth-agents",
|
|
27
27
|
"ai-agent",
|
|
28
28
|
"did",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"type": "git",
|
|
39
39
|
"url": "https://github.com/AgenthAgent/auth-agents-sdk-node"
|
|
40
40
|
},
|
|
41
|
-
"homepage": "https://
|
|
41
|
+
"homepage": "https://usevigil.dev",
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"tsup": "^8.0.0",
|
|
44
44
|
"typescript": "^5.0.0"
|