vestauth 0.11.2 → 0.12.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/CHANGELOG.md +9 -2
- package/README.md +11 -0
- package/package.json +3 -1
- package/src/cli/actions/agent/init.js +1 -1
- package/src/cli/actions/agent/rotate.js +1 -1
- package/src/cli/commands/agent.js +2 -0
- package/src/lib/helpers/agentInit.js +8 -2
- package/src/lib/helpers/agentRotate.js +4 -2
- package/src/lib/helpers/normalizeAgentHostname.js +13 -0
- package/src/lib/main.d.ts +138 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,9 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
-
[Unreleased](https://github.com/vestauth/vestauth/compare/v0.
|
|
5
|
+
[Unreleased](https://github.com/vestauth/vestauth/compare/v0.12.0...main)
|
|
6
6
|
|
|
7
|
-
## [0.
|
|
7
|
+
## [0.12.0](https://github.com/vestauth/vestauth/compare/v0.11.2...v0.12.0) (2026-02-17)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
* Add `--hostname` flag for `agent init` ([#17](https://github.com/vestauth/vestauth/pull/17) & [#18](https://github.com/vestauth/vestauth/pull/18))
|
|
12
|
+
* Add types file ([#16](https://github.com/vestauth/vestauth/pull/16))
|
|
13
|
+
|
|
14
|
+
## [0.11.2](https://github.com/vestauth/vestauth/compare/v0.11.0...v0.11.2) (2026-02-17)
|
|
8
15
|
|
|
9
16
|
### Removed
|
|
10
17
|
|
package/README.md
CHANGED
|
@@ -208,6 +208,17 @@ $ vestauth agent init
|
|
|
208
208
|
⮕ next run: [vestauth agent curl https://api.vestauth.com/whoami]
|
|
209
209
|
```
|
|
210
210
|
|
|
211
|
+
</details>
|
|
212
|
+
<details><summary>`agent init --hostname`</summary><br>
|
|
213
|
+
|
|
214
|
+
Use `--hostname` to override the agent API hostname (defaults to `AGENT_HOSTNAME`, then `api.vestauth.com`):
|
|
215
|
+
|
|
216
|
+
```sh
|
|
217
|
+
$ vestauth agent init --hostname https://vestauth.yoursite.com
|
|
218
|
+
✔ agent created (.env/AGENT_UID=agent-609a4fd2ebf4e6347108c517)
|
|
219
|
+
⮕ next run: [vestauth agent curl https://api.vestauth.com/whoami]
|
|
220
|
+
```
|
|
221
|
+
|
|
211
222
|
</details>
|
|
212
223
|
<details><summary>`agent curl`</summary><br>
|
|
213
224
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vestauth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "auth for agents–from the creator of dotenvx",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"vestauth",
|
|
@@ -23,8 +23,10 @@
|
|
|
23
23
|
],
|
|
24
24
|
"license": "BSD-3-Clause",
|
|
25
25
|
"main": "src/lib/main.js",
|
|
26
|
+
"types": "./src/lib/main.d.ts",
|
|
26
27
|
"exports": {
|
|
27
28
|
".": {
|
|
29
|
+
"types": "./src/lib/main.d.ts",
|
|
28
30
|
"require": "./src/lib/main.js",
|
|
29
31
|
"default": "./src/lib/main.js"
|
|
30
32
|
},
|
|
@@ -8,7 +8,7 @@ async function init () {
|
|
|
8
8
|
const options = this.opts()
|
|
9
9
|
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
10
10
|
|
|
11
|
-
const output = await agent.init()
|
|
11
|
+
const output = await agent.init(options.hostname)
|
|
12
12
|
|
|
13
13
|
if (output.isNew) {
|
|
14
14
|
logger.success(`✔ agent created (${output.path}/AGENT_UID=${output.AGENT_UID})`)
|
|
@@ -10,7 +10,7 @@ async function rotate () {
|
|
|
10
10
|
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
11
11
|
|
|
12
12
|
const uid = options.uid || options.id || env('AGENT_UID') || env('AGENT_ID')
|
|
13
|
-
const output = await agent.rotate(uid, options.privateJwk, options.tag, options.nonce)
|
|
13
|
+
const output = await agent.rotate(uid, options.privateJwk, options.tag, options.nonce, options.hostname)
|
|
14
14
|
|
|
15
15
|
logger.success(`✔ agent keys rotated (${output.path}/AGENT_UID=${output.AGENT_UID})`)
|
|
16
16
|
logger.help('⮕ next run: [vestauth agent curl https://api.vestauth.com/whoami]')
|
|
@@ -11,6 +11,7 @@ agent
|
|
|
11
11
|
const initAction = require('./../actions/agent/init')
|
|
12
12
|
agent.command('init')
|
|
13
13
|
.description('create agent')
|
|
14
|
+
.option('--hostname <hostname>', 'agent API hostname')
|
|
14
15
|
.action(initAction)
|
|
15
16
|
|
|
16
17
|
// vestauth agent curl
|
|
@@ -42,6 +43,7 @@ agent.command('rotate')
|
|
|
42
43
|
.description('rotate keypair')
|
|
43
44
|
.option('--uid, --id <uid>', 'uid (string)', env('AGENT_UID') || env('AGENT_ID'))
|
|
44
45
|
.option('--private-jwk <privateJwk>', 'AGENT_PRIVATE_JWK (default)', env('AGENT_PRIVATE_JWK'))
|
|
46
|
+
.option('--hostname <hostname>', 'agent API hostname')
|
|
45
47
|
.option('--tag <tag>', 'web-bot-auth (default) | web-bot-auth', 'web-bot-auth')
|
|
46
48
|
.option('--nonce <nonce>', 'null (default)')
|
|
47
49
|
.option('--pp, --pretty-print', 'pretty print output')
|
|
@@ -2,10 +2,13 @@ const dotenvx = require('@dotenvx/dotenvx')
|
|
|
2
2
|
const identity = require('./identity')
|
|
3
3
|
const keypair = require('./keypair')
|
|
4
4
|
const touch = require('./touch')
|
|
5
|
+
const normalizeAgentHostname = require('./normalizeAgentHostname')
|
|
5
6
|
const PostRegister = require('../api/postRegister')
|
|
6
7
|
|
|
7
|
-
async function agentInit () {
|
|
8
|
+
async function agentInit (hostname = null) {
|
|
8
9
|
const envPath = '.env'
|
|
10
|
+
const normalizedHostname = normalizeAgentHostname(hostname)
|
|
11
|
+
const shouldPersistHostname = Boolean(hostname && String(hostname).trim())
|
|
9
12
|
|
|
10
13
|
// keypair
|
|
11
14
|
const currentPrivateJwk = identity(false).privateJwk
|
|
@@ -16,9 +19,12 @@ async function agentInit () {
|
|
|
16
19
|
// must come before registration so that registration can send headers
|
|
17
20
|
dotenvx.set('AGENT_PUBLIC_JWK', JSON.stringify(kp.publicJwk), { path: envPath, plain: true, quiet: true })
|
|
18
21
|
dotenvx.set('AGENT_PRIVATE_JWK', JSON.stringify(kp.privateJwk), { path: envPath, plain: true, quiet: true })
|
|
22
|
+
if (shouldPersistHostname) {
|
|
23
|
+
dotenvx.set('AGENT_HOSTNAME', new URL(normalizedHostname).host, { path: envPath, plain: true, quiet: true })
|
|
24
|
+
}
|
|
19
25
|
|
|
20
26
|
// register agent
|
|
21
|
-
const agent = await new PostRegister(
|
|
27
|
+
const agent = await new PostRegister(normalizedHostname, kp.publicJwk).run()
|
|
22
28
|
dotenvx.set('AGENT_UID', agent.uid, { path: envPath, plain: true, quiet: true })
|
|
23
29
|
|
|
24
30
|
return {
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
const dotenvx = require('@dotenvx/dotenvx')
|
|
2
2
|
const keypair = require('./keypair')
|
|
3
|
+
const normalizeAgentHostname = require('./normalizeAgentHostname')
|
|
3
4
|
const PostRotate = require('../api/postRotate')
|
|
4
5
|
|
|
5
|
-
async function agentRotate (uid, privateJwk, tag = 'web-bot-auth', nonce = null) {
|
|
6
|
+
async function agentRotate (uid, privateJwk, tag = 'web-bot-auth', nonce = null, hostname = null) {
|
|
6
7
|
const envPath = '.env'
|
|
8
|
+
const rotateUrl = normalizeAgentHostname(hostname)
|
|
7
9
|
|
|
8
10
|
// new keypair
|
|
9
11
|
const newKp = keypair()
|
|
10
12
|
|
|
11
13
|
// rotate jwk
|
|
12
|
-
const agent = await new PostRotate(
|
|
14
|
+
const agent = await new PostRotate(rotateUrl, newKp.publicJwk, uid, privateJwk).run()
|
|
13
15
|
|
|
14
16
|
dotenvx.set('AGENT_PUBLIC_JWK', JSON.stringify(newKp.publicJwk), { path: envPath, plain: true, quiet: true })
|
|
15
17
|
dotenvx.set('AGENT_PRIVATE_JWK', JSON.stringify(newKp.privateJwk), { path: envPath, plain: true, quiet: true })
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function normalizeAgentHostname (hostname = null) {
|
|
2
|
+
const value = (hostname || process.env.AGENT_HOSTNAME || 'api.vestauth.com').trim()
|
|
3
|
+
const candidate = /^https?:\/\//i.test(value) ? value : `https://${value}`
|
|
4
|
+
const url = new URL(candidate)
|
|
5
|
+
|
|
6
|
+
if (url.pathname !== '/' || url.search || url.hash) {
|
|
7
|
+
throw new Error('invalid --hostname. path/query/hash are not allowed')
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return url.origin
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
module.exports = normalizeAgentHostname
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
export type HttpMethod =
|
|
2
|
+
| 'GET'
|
|
3
|
+
| 'POST'
|
|
4
|
+
| 'PUT'
|
|
5
|
+
| 'PATCH'
|
|
6
|
+
| 'DELETE'
|
|
7
|
+
| 'OPTIONS'
|
|
8
|
+
| 'HEAD'
|
|
9
|
+
| (string & {})
|
|
10
|
+
|
|
11
|
+
export type HeaderValue = string | string[]
|
|
12
|
+
export type HeaderBag = Record<string, HeaderValue | undefined>
|
|
13
|
+
|
|
14
|
+
/** Minimal JWK shape used by Vestauth (Ed25519 OKP). */
|
|
15
|
+
export interface OkpEd25519PublicJwk {
|
|
16
|
+
kty: 'OKP'
|
|
17
|
+
crv: 'Ed25519'
|
|
18
|
+
x: string
|
|
19
|
+
kid?: string
|
|
20
|
+
[prop: string]: unknown
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Minimal private JWK shape used by Vestauth (Ed25519 OKP). */
|
|
24
|
+
export interface OkpEd25519PrivateJwk extends OkpEd25519PublicJwk {
|
|
25
|
+
d: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type PublicJwk = OkpEd25519PublicJwk
|
|
29
|
+
export type PrivateJwk = OkpEd25519PrivateJwk
|
|
30
|
+
|
|
31
|
+
export interface Keypair {
|
|
32
|
+
publicJwk: PublicJwk
|
|
33
|
+
privateJwk: PrivateJwk
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface SignatureHeaders {
|
|
37
|
+
Signature: string
|
|
38
|
+
'Signature-Input': string
|
|
39
|
+
'Signature-Agent': string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface VerifyResult {
|
|
43
|
+
uid?: string
|
|
44
|
+
kid?: string
|
|
45
|
+
public_jwk?: PublicJwk
|
|
46
|
+
well_known_url?: string
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface AgentApi {
|
|
50
|
+
/**
|
|
51
|
+
* Creates (or reuses) an Ed25519 keypair, registers the agent, and writes to `.env`.
|
|
52
|
+
*/
|
|
53
|
+
init(): Promise<{
|
|
54
|
+
AGENT_PUBLIC_JWK: PublicJwk
|
|
55
|
+
AGENT_UID: string
|
|
56
|
+
path: string
|
|
57
|
+
isNew: boolean
|
|
58
|
+
}>
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Generates RFC 9421 request signature headers.
|
|
62
|
+
*
|
|
63
|
+
* When `uid` / `privateJwk` are omitted, Vestauth reads them from `.env`.
|
|
64
|
+
*/
|
|
65
|
+
headers(
|
|
66
|
+
httpMethod: HttpMethod,
|
|
67
|
+
uri: string,
|
|
68
|
+
uid?: string | null,
|
|
69
|
+
privateJwk?: string | null,
|
|
70
|
+
tag?: string,
|
|
71
|
+
nonce?: string | null
|
|
72
|
+
): Promise<SignatureHeaders>
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Rotates the agent keypair and writes the new keys to `.env`.
|
|
76
|
+
*/
|
|
77
|
+
rotate(
|
|
78
|
+
uid: string,
|
|
79
|
+
privateJwk: string,
|
|
80
|
+
tag?: string,
|
|
81
|
+
nonce?: string | null
|
|
82
|
+
): Promise<{
|
|
83
|
+
AGENT_PUBLIC_JWK: PublicJwk
|
|
84
|
+
AGENT_UID: string
|
|
85
|
+
path: string
|
|
86
|
+
}>
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface ProviderApi {
|
|
90
|
+
/**
|
|
91
|
+
* Verifies a signed request (fetching the agent's discovery keys when needed).
|
|
92
|
+
*/
|
|
93
|
+
verify(httpMethod: HttpMethod, uri: string, headers?: HeaderBag): Promise<VerifyResult>
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface PrimitivesApi {
|
|
97
|
+
/**
|
|
98
|
+
* Creates an Ed25519 keypair. If `existingPrivateJwk` is provided, it is reused.
|
|
99
|
+
*/
|
|
100
|
+
keypair(existingPrivateJwk?: string, prefix?: string): Keypair
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Generates RFC 9421 request signature headers.
|
|
104
|
+
*/
|
|
105
|
+
headers(
|
|
106
|
+
httpMethod: HttpMethod,
|
|
107
|
+
uri: string,
|
|
108
|
+
uid: string,
|
|
109
|
+
privateJwk: string,
|
|
110
|
+
tag?: string,
|
|
111
|
+
nonce?: string | null
|
|
112
|
+
): Promise<SignatureHeaders>
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Verifies a signed request.
|
|
116
|
+
*
|
|
117
|
+
* When `publicJwk` is not provided, Vestauth will attempt to resolve it via
|
|
118
|
+
* `Signature-Agent` discovery.
|
|
119
|
+
*/
|
|
120
|
+
verify(
|
|
121
|
+
httpMethod: HttpMethod,
|
|
122
|
+
uri: string,
|
|
123
|
+
headers?: HeaderBag,
|
|
124
|
+
publicJwk?: PublicJwk
|
|
125
|
+
): Promise<VerifyResult>
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export const agent: AgentApi
|
|
129
|
+
export const provider: ProviderApi
|
|
130
|
+
export const primitives: PrimitivesApi
|
|
131
|
+
|
|
132
|
+
declare const _default: {
|
|
133
|
+
agent: AgentApi
|
|
134
|
+
provider: ProviderApi
|
|
135
|
+
primitives: PrimitivesApi
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export default _default
|