auth-agents 0.1.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +144 -24
- package/dist/index.d.mts +47 -5
- package/dist/index.d.ts +47 -5
- package/dist/index.js +65 -4
- package/dist/index.mjs +65 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,10 +23,106 @@ 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
|
|
@@ -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
|
|
|
@@ -80,50 +177,73 @@ 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.getagentauth.com`)
|
|
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
|
+
|
|
125
232
|
### `client.register(input)` — Register a new agent identity
|
|
126
233
|
|
|
234
|
+
`input.public_key_jwk` is optional. Omit it for server-generated keys (Flow A). Provide it for BYOK (Flow B).
|
|
235
|
+
|
|
236
|
+
Returns `RegisterResult`:
|
|
237
|
+
```typescript
|
|
238
|
+
{
|
|
239
|
+
did: string
|
|
240
|
+
credential: string
|
|
241
|
+
key_fingerprint: string
|
|
242
|
+
key_origin?: "server_generated" | "client_provided"
|
|
243
|
+
private_key_jwk?: { kty, crv, x, d } // only present for server_generated
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
127
247
|
### `client.challenge(did)` — Request an auth challenge
|
|
128
248
|
|
|
129
249
|
### `client.authenticate(input)` — Submit signed challenge
|
package/dist/index.d.mts
CHANGED
|
@@ -2,6 +2,20 @@ interface AuthAgentsConfig {
|
|
|
2
2
|
/** Base URL of the Agent Auth API. Defaults to https://auth.getagentauth.com */
|
|
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,6 +26,7 @@ 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;
|
|
@@ -34,6 +49,7 @@ interface RegisterResult {
|
|
|
34
49
|
did: string;
|
|
35
50
|
credential: string;
|
|
36
51
|
key_fingerprint: string;
|
|
52
|
+
key_origin?: "server_generated" | "client_provided";
|
|
37
53
|
private_key_jwk?: {
|
|
38
54
|
kty: string;
|
|
39
55
|
crv: string;
|
|
@@ -75,6 +91,31 @@ type AuthVerifyResponse = AuthVerifyResult | AuthVerifyError;
|
|
|
75
91
|
declare class AuthAgents {
|
|
76
92
|
private baseUrl;
|
|
77
93
|
constructor(config?: AuthAgentsConfig);
|
|
94
|
+
/**
|
|
95
|
+
* Generate an Ed25519 key pair using the Web Crypto API.
|
|
96
|
+
* Use the returned public key JWK for BYOK registration and the private key
|
|
97
|
+
* JWK with signChallenge() to complete headless authentication.
|
|
98
|
+
*
|
|
99
|
+
* SECURITY: Store the private key securely. Never transmit it over the wire.
|
|
100
|
+
*
|
|
101
|
+
* @returns Ed25519 key pair in JWK format
|
|
102
|
+
*/
|
|
103
|
+
static generateKeyPair(): Promise<Ed25519KeyPair>;
|
|
104
|
+
/**
|
|
105
|
+
* Sign an authentication challenge nonce with an Ed25519 private key.
|
|
106
|
+
* The nonce is signed as UTF-8 encoded text (NOT hex-decoded bytes).
|
|
107
|
+
* Returns a base64url-encoded signature string.
|
|
108
|
+
*
|
|
109
|
+
* @param privateKeyJwk - The agent's private key in JWK format (must include `d`)
|
|
110
|
+
* @param nonce - The challenge nonce string returned by client.challenge()
|
|
111
|
+
* @returns base64url-encoded Ed25519 signature
|
|
112
|
+
*/
|
|
113
|
+
static signChallenge(privateKeyJwk: {
|
|
114
|
+
kty: string;
|
|
115
|
+
crv: string;
|
|
116
|
+
x: string;
|
|
117
|
+
d: string;
|
|
118
|
+
}, nonce: string): Promise<string>;
|
|
78
119
|
/**
|
|
79
120
|
* Verify a VC-JWT credential issued by Agent Auth.
|
|
80
121
|
*
|
|
@@ -83,11 +124,12 @@ declare class AuthAgents {
|
|
|
83
124
|
*/
|
|
84
125
|
verify(credential: string): Promise<VerifyResponse>;
|
|
85
126
|
/**
|
|
86
|
-
* Register a new agent identity.
|
|
87
|
-
* and returns
|
|
127
|
+
* Register a new agent identity. By default the server generates an Ed25519
|
|
128
|
+
* keypair and returns the private key. Pass `public_key_jwk` to use your own
|
|
129
|
+
* key (BYOK) — in that case no private key is returned.
|
|
88
130
|
*
|
|
89
|
-
* @param input - Agent metadata
|
|
90
|
-
* @returns DID, credential, and private key
|
|
131
|
+
* @param input - Agent metadata and optional public key JWK for BYOK
|
|
132
|
+
* @returns DID, credential, key_origin, and private key if server-generated
|
|
91
133
|
*/
|
|
92
134
|
register(input: RegisterInput): Promise<RegisterResult>;
|
|
93
135
|
/**
|
|
@@ -111,4 +153,4 @@ declare class AuthAgents {
|
|
|
111
153
|
*/
|
|
112
154
|
declare function verify(credential: string): Promise<VerifyResponse>;
|
|
113
155
|
|
|
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 };
|
|
156
|
+
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
|
@@ -2,6 +2,20 @@ interface AuthAgentsConfig {
|
|
|
2
2
|
/** Base URL of the Agent Auth API. Defaults to https://auth.getagentauth.com */
|
|
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,6 +26,7 @@ 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;
|
|
@@ -34,6 +49,7 @@ interface RegisterResult {
|
|
|
34
49
|
did: string;
|
|
35
50
|
credential: string;
|
|
36
51
|
key_fingerprint: string;
|
|
52
|
+
key_origin?: "server_generated" | "client_provided";
|
|
37
53
|
private_key_jwk?: {
|
|
38
54
|
kty: string;
|
|
39
55
|
crv: string;
|
|
@@ -75,6 +91,31 @@ type AuthVerifyResponse = AuthVerifyResult | AuthVerifyError;
|
|
|
75
91
|
declare class AuthAgents {
|
|
76
92
|
private baseUrl;
|
|
77
93
|
constructor(config?: AuthAgentsConfig);
|
|
94
|
+
/**
|
|
95
|
+
* Generate an Ed25519 key pair using the Web Crypto API.
|
|
96
|
+
* Use the returned public key JWK for BYOK registration and the private key
|
|
97
|
+
* JWK with signChallenge() to complete headless authentication.
|
|
98
|
+
*
|
|
99
|
+
* SECURITY: Store the private key securely. Never transmit it over the wire.
|
|
100
|
+
*
|
|
101
|
+
* @returns Ed25519 key pair in JWK format
|
|
102
|
+
*/
|
|
103
|
+
static generateKeyPair(): Promise<Ed25519KeyPair>;
|
|
104
|
+
/**
|
|
105
|
+
* Sign an authentication challenge nonce with an Ed25519 private key.
|
|
106
|
+
* The nonce is signed as UTF-8 encoded text (NOT hex-decoded bytes).
|
|
107
|
+
* Returns a base64url-encoded signature string.
|
|
108
|
+
*
|
|
109
|
+
* @param privateKeyJwk - The agent's private key in JWK format (must include `d`)
|
|
110
|
+
* @param nonce - The challenge nonce string returned by client.challenge()
|
|
111
|
+
* @returns base64url-encoded Ed25519 signature
|
|
112
|
+
*/
|
|
113
|
+
static signChallenge(privateKeyJwk: {
|
|
114
|
+
kty: string;
|
|
115
|
+
crv: string;
|
|
116
|
+
x: string;
|
|
117
|
+
d: string;
|
|
118
|
+
}, nonce: string): Promise<string>;
|
|
78
119
|
/**
|
|
79
120
|
* Verify a VC-JWT credential issued by Agent Auth.
|
|
80
121
|
*
|
|
@@ -83,11 +124,12 @@ declare class AuthAgents {
|
|
|
83
124
|
*/
|
|
84
125
|
verify(credential: string): Promise<VerifyResponse>;
|
|
85
126
|
/**
|
|
86
|
-
* Register a new agent identity.
|
|
87
|
-
* and returns
|
|
127
|
+
* Register a new agent identity. By default the server generates an Ed25519
|
|
128
|
+
* keypair and returns the private key. Pass `public_key_jwk` to use your own
|
|
129
|
+
* key (BYOK) — in that case no private key is returned.
|
|
88
130
|
*
|
|
89
|
-
* @param input - Agent metadata
|
|
90
|
-
* @returns DID, credential, and private key
|
|
131
|
+
* @param input - Agent metadata and optional public key JWK for BYOK
|
|
132
|
+
* @returns DID, credential, key_origin, and private key if server-generated
|
|
91
133
|
*/
|
|
92
134
|
register(input: RegisterInput): Promise<RegisterResult>;
|
|
93
135
|
/**
|
|
@@ -111,4 +153,4 @@ declare class AuthAgents {
|
|
|
111
153
|
*/
|
|
112
154
|
declare function verify(credential: string): Promise<VerifyResponse>;
|
|
113
155
|
|
|
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 };
|
|
156
|
+
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
|
@@ -29,6 +29,66 @@ var AuthAgents = class {
|
|
|
29
29
|
constructor(config) {
|
|
30
30
|
this.baseUrl = (config?.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
31
31
|
}
|
|
32
|
+
// ---- Static Crypto Helpers ---------------------------------------------
|
|
33
|
+
/**
|
|
34
|
+
* Generate an Ed25519 key pair using the Web Crypto API.
|
|
35
|
+
* Use the returned public key JWK for BYOK registration and the private key
|
|
36
|
+
* JWK with signChallenge() to complete headless authentication.
|
|
37
|
+
*
|
|
38
|
+
* SECURITY: Store the private key securely. Never transmit it over the wire.
|
|
39
|
+
*
|
|
40
|
+
* @returns Ed25519 key pair in JWK format
|
|
41
|
+
*/
|
|
42
|
+
static async generateKeyPair() {
|
|
43
|
+
const keyPair = await crypto.subtle.generateKey(
|
|
44
|
+
"Ed25519",
|
|
45
|
+
true,
|
|
46
|
+
// extractable
|
|
47
|
+
["sign", "verify"]
|
|
48
|
+
);
|
|
49
|
+
const publicJwk = await crypto.subtle.exportKey("jwk", keyPair.publicKey);
|
|
50
|
+
const privateJwk = await crypto.subtle.exportKey("jwk", keyPair.privateKey);
|
|
51
|
+
return {
|
|
52
|
+
publicKeyJwk: {
|
|
53
|
+
kty: publicJwk.kty,
|
|
54
|
+
crv: publicJwk.crv,
|
|
55
|
+
x: publicJwk.x
|
|
56
|
+
},
|
|
57
|
+
privateKeyJwk: {
|
|
58
|
+
kty: privateJwk.kty,
|
|
59
|
+
crv: privateJwk.crv,
|
|
60
|
+
x: privateJwk.x,
|
|
61
|
+
d: privateJwk.d
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Sign an authentication challenge nonce with an Ed25519 private key.
|
|
67
|
+
* The nonce is signed as UTF-8 encoded text (NOT hex-decoded bytes).
|
|
68
|
+
* Returns a base64url-encoded signature string.
|
|
69
|
+
*
|
|
70
|
+
* @param privateKeyJwk - The agent's private key in JWK format (must include `d`)
|
|
71
|
+
* @param nonce - The challenge nonce string returned by client.challenge()
|
|
72
|
+
* @returns base64url-encoded Ed25519 signature
|
|
73
|
+
*/
|
|
74
|
+
static async signChallenge(privateKeyJwk, nonce) {
|
|
75
|
+
const key = await crypto.subtle.importKey(
|
|
76
|
+
"jwk",
|
|
77
|
+
{ ...privateKeyJwk, key_ops: ["sign"] },
|
|
78
|
+
"Ed25519",
|
|
79
|
+
false,
|
|
80
|
+
["sign"]
|
|
81
|
+
);
|
|
82
|
+
const data = new TextEncoder().encode(nonce);
|
|
83
|
+
const signatureBuffer = await crypto.subtle.sign("Ed25519", key, data);
|
|
84
|
+
const bytes = new Uint8Array(signatureBuffer);
|
|
85
|
+
let binary = "";
|
|
86
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
87
|
+
binary += String.fromCharCode(bytes[i]);
|
|
88
|
+
}
|
|
89
|
+
const base64 = btoa(binary);
|
|
90
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
91
|
+
}
|
|
32
92
|
// ---- Credential Verification (for websites) ----------------------------
|
|
33
93
|
/**
|
|
34
94
|
* Verify a VC-JWT credential issued by Agent Auth.
|
|
@@ -46,11 +106,12 @@ var AuthAgents = class {
|
|
|
46
106
|
}
|
|
47
107
|
// ---- Agent Registration ------------------------------------------------
|
|
48
108
|
/**
|
|
49
|
-
* Register a new agent identity.
|
|
50
|
-
* and returns
|
|
109
|
+
* Register a new agent identity. By default the server generates an Ed25519
|
|
110
|
+
* keypair and returns the private key. Pass `public_key_jwk` to use your own
|
|
111
|
+
* key (BYOK) — in that case no private key is returned.
|
|
51
112
|
*
|
|
52
|
-
* @param input - Agent metadata
|
|
53
|
-
* @returns DID, credential, and private key
|
|
113
|
+
* @param input - Agent metadata and optional public key JWK for BYOK
|
|
114
|
+
* @returns DID, credential, key_origin, and private key if server-generated
|
|
54
115
|
*/
|
|
55
116
|
async register(input) {
|
|
56
117
|
const res = await fetch(`${this.baseUrl}/v1/identities`, {
|
package/dist/index.mjs
CHANGED
|
@@ -4,6 +4,66 @@ var AuthAgents = class {
|
|
|
4
4
|
constructor(config) {
|
|
5
5
|
this.baseUrl = (config?.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
6
6
|
}
|
|
7
|
+
// ---- Static Crypto Helpers ---------------------------------------------
|
|
8
|
+
/**
|
|
9
|
+
* Generate an Ed25519 key pair using the Web Crypto API.
|
|
10
|
+
* Use the returned public key JWK for BYOK registration and the private key
|
|
11
|
+
* JWK with signChallenge() to complete headless authentication.
|
|
12
|
+
*
|
|
13
|
+
* SECURITY: Store the private key securely. Never transmit it over the wire.
|
|
14
|
+
*
|
|
15
|
+
* @returns Ed25519 key pair in JWK format
|
|
16
|
+
*/
|
|
17
|
+
static async generateKeyPair() {
|
|
18
|
+
const keyPair = await crypto.subtle.generateKey(
|
|
19
|
+
"Ed25519",
|
|
20
|
+
true,
|
|
21
|
+
// extractable
|
|
22
|
+
["sign", "verify"]
|
|
23
|
+
);
|
|
24
|
+
const publicJwk = await crypto.subtle.exportKey("jwk", keyPair.publicKey);
|
|
25
|
+
const privateJwk = await crypto.subtle.exportKey("jwk", keyPair.privateKey);
|
|
26
|
+
return {
|
|
27
|
+
publicKeyJwk: {
|
|
28
|
+
kty: publicJwk.kty,
|
|
29
|
+
crv: publicJwk.crv,
|
|
30
|
+
x: publicJwk.x
|
|
31
|
+
},
|
|
32
|
+
privateKeyJwk: {
|
|
33
|
+
kty: privateJwk.kty,
|
|
34
|
+
crv: privateJwk.crv,
|
|
35
|
+
x: privateJwk.x,
|
|
36
|
+
d: privateJwk.d
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Sign an authentication challenge nonce with an Ed25519 private key.
|
|
42
|
+
* The nonce is signed as UTF-8 encoded text (NOT hex-decoded bytes).
|
|
43
|
+
* Returns a base64url-encoded signature string.
|
|
44
|
+
*
|
|
45
|
+
* @param privateKeyJwk - The agent's private key in JWK format (must include `d`)
|
|
46
|
+
* @param nonce - The challenge nonce string returned by client.challenge()
|
|
47
|
+
* @returns base64url-encoded Ed25519 signature
|
|
48
|
+
*/
|
|
49
|
+
static async signChallenge(privateKeyJwk, nonce) {
|
|
50
|
+
const key = await crypto.subtle.importKey(
|
|
51
|
+
"jwk",
|
|
52
|
+
{ ...privateKeyJwk, key_ops: ["sign"] },
|
|
53
|
+
"Ed25519",
|
|
54
|
+
false,
|
|
55
|
+
["sign"]
|
|
56
|
+
);
|
|
57
|
+
const data = new TextEncoder().encode(nonce);
|
|
58
|
+
const signatureBuffer = await crypto.subtle.sign("Ed25519", key, data);
|
|
59
|
+
const bytes = new Uint8Array(signatureBuffer);
|
|
60
|
+
let binary = "";
|
|
61
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
62
|
+
binary += String.fromCharCode(bytes[i]);
|
|
63
|
+
}
|
|
64
|
+
const base64 = btoa(binary);
|
|
65
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
66
|
+
}
|
|
7
67
|
// ---- Credential Verification (for websites) ----------------------------
|
|
8
68
|
/**
|
|
9
69
|
* Verify a VC-JWT credential issued by Agent Auth.
|
|
@@ -21,11 +81,12 @@ var AuthAgents = class {
|
|
|
21
81
|
}
|
|
22
82
|
// ---- Agent Registration ------------------------------------------------
|
|
23
83
|
/**
|
|
24
|
-
* Register a new agent identity.
|
|
25
|
-
* and returns
|
|
84
|
+
* Register a new agent identity. By default the server generates an Ed25519
|
|
85
|
+
* keypair and returns the private key. Pass `public_key_jwk` to use your own
|
|
86
|
+
* key (BYOK) — in that case no private key is returned.
|
|
26
87
|
*
|
|
27
|
-
* @param input - Agent metadata
|
|
28
|
-
* @returns DID, credential, and private key
|
|
88
|
+
* @param input - Agent metadata and optional public key JWK for BYOK
|
|
89
|
+
* @returns DID, credential, key_origin, and private key if server-generated
|
|
29
90
|
*/
|
|
30
91
|
async register(input) {
|
|
31
92
|
const res = await fetch(`${this.baseUrl}/v1/identities`, {
|
package/package.json
CHANGED