vestauth 0.7.1 → 0.7.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/CHANGELOG.md CHANGED
@@ -2,7 +2,19 @@
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.7.1...main)
5
+ [Unreleased](https://github.com/vestauth/vestauth/compare/v0.7.3...main)
6
+
7
+ ## [0.7.3](https://github.com/vestauth/vestauth/compare/v0.7.2...v0.7.3) (2026-02-04)
8
+
9
+ ### Changed
10
+
11
+ * Improved handling of headers
12
+
13
+ ## [0.7.2](https://github.com/vestauth/vestauth/compare/v0.7.1...v0.7.2) (2026-02-04)
14
+
15
+ ### Changed
16
+
17
+ * Handle headers in a more flexible way
6
18
 
7
19
  ## [0.7.1](https://github.com/vestauth/vestauth/compare/v0.7.0...v0.7.1) (2026-02-04)
8
20
 
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  *auth for agents*–from the creator of [`dotenvx`](https://github.com/dotenvx/dotenvx).
4
4
 
5
- * identity
5
+ * identity (cryptographic)
6
6
  * authentication
7
7
  * verification
8
8
 
@@ -11,59 +11,128 @@
11
11
  ### Quickstart [![npm version](https://img.shields.io/npm/v/vestauth.svg)](https://www.npmjs.com/package/vestauth) [![downloads](https://img.shields.io/npm/dw/vestauth)](https://www.npmjs.com/package/vestauth)
12
12
 
13
13
  ```sh
14
- curl -sfS https://vestauth.sh | sh
14
+ npm i -g vestauth
15
15
  ```
16
16
 
17
17
  ```sh
18
18
  vestauth agent init
19
- vestauth agent curl https://api.vestauth.com/whoami
20
19
  ```
21
20
 
22
21
   
23
22
 
24
- or install as npm - *unlocks vestauth inside code!*
23
+ or install globally - *unlocks vestauth for any agent, agent tool, or agent framework!*
25
24
 
26
- <details><summary>with npm 📦</summary><br>
25
+ <details><summary>with curl 🌐 </summary><br>
27
26
 
28
27
  ```sh
29
- npm install vestauth --save
28
+ curl -sfS https://vestauth.sh | sh
29
+ vestauth help
30
30
  ```
31
31
 
32
+ [![curl installs](https://img.shields.io/endpoint?url=https://vestauth.sh/stats/curl&label=curl%20installs)](https://github.com/vestauth/vestauth.sh/blob/main/install.sh)
33
+
32
34
  &nbsp;
33
35
 
34
36
  </details>
35
37
 
36
- ## Agent
38
+ <details><summary>with github releases 🐙</summary><br>
39
+
40
+ ```sh
41
+ curl -L -o vestauth.tar.gz "https://github.com/vestauth/vestauth/releases/latest/download/vestauth-$(uname -s)-$(uname -m).tar.gz"
42
+ tar -xzf vestauth.tar.gz
43
+ ./vestauth help
44
+ ```
45
+
46
+ [![github releases](https://img.shields.io/github/downloads/vestauth/vestauth/total)](https://github.com/vestauth/vestauth/releases)
47
+
48
+ &nbsp;
49
+
50
+ </details>
37
51
 
38
- > Initialize your agent and make authenticated curl calls to vestauth providers.
52
+ <details><summary>or windows 🪟</summary><br>
53
+
54
+ Download [the windows executable](https://github.com/vestauth/vestauth/releases) directly from the [releases page](https://github.com/vestauth/vestauth/releases).
55
+
56
+ > * [vestauth-windows-amd64.zip
57
+ ](https://github.com/vestauth/releases/raw/main/latest/vestauth-windows-amd64.zip)
58
+ > * [vestauth-windows-x86_64.zip
59
+ ](https://github.com/vestauth/releases/raw/main/latest/vestauth-windows-x86_64.zip)
60
+
61
+ (unzip to extract `vestauth.exe`)
62
+
63
+ </details>
64
+
65
+ &nbsp;
66
+
67
+ ## Identity
68
+
69
+ > Give your agent its cryptographic identity.
39
70
 
40
71
  ```sh
72
+ $ mkdir your-agent
73
+ $ cd your-agent
74
+
41
75
  $ vestauth agent init
42
- $ vestauth agent curl https://ping.vestauth.com/ping
76
+ agent created (.env/AGENT_ID=agent-4b94ccd425e939fac5016b6b)
43
77
  ```
44
78
 
45
- More examples
79
+ <details><summary>learn more</summary><br>
46
80
 
47
- *coming soon*
81
+ This populates a `.env` file with an `AGENT_PUBLIC_JWK`, `AGENT_PRIVATE_JWK`, and `AGENT_ID`.
48
82
 
49
- ## Provider
83
+ ```ini
84
+ # example
85
+ AGENT_PUBLIC_JWK="{"crv":"Ed25519","x":"py2xNaAfjKZiau-jtmJls6h_3n8xJ1Ur0ie-n9b8zWg","kty":"OKP","kid":"B0u80Gw28W9U2Jl5t_EBiWeBajO2104kOYZ9Ikucl5I"}"
86
+ AGENT_PRIVATE_JWK="{"crv":"Ed25519","d":"Z9vbwN-3eiFMVv_TPWXOxqSMJAT21kZvejWi72yiAaQ","x":"py2xNaAfjKZiau-jtmJls6h_3n8xJ1Ur0ie-n9b8zWg","kty":"OKP","kid":"B0u80Gw28W9U2Jl5t_EBiWeBajO2104kOYZ9Ikucl5I"}"
87
+ AGENT_ID="agent-4b94ccd425e939fac5016b6b"
88
+ ```
50
89
 
51
- > As a provider of agentic tools, authenticate agents through cryptographic verification.
90
+ * The `AGENT_PUBLIC_KEY` is auto-hosted to its own [`/.well-known/http-message-signatures-directory`](https://datatracker.ietf.org/doc/html/draft-meunier-http-message-signatures-directory-04#appendix-A) for discovery purposes.
91
+ * The `AGENT_PRIVATE_KEY` must NOT be shared and is used to sign requests according to [RFC 9421](https://datatracker.ietf.org/doc/rfc9421/).
92
+ * The `AGENT_ID` contributes to building the [FQDN for the `Signature-Agent` header](https://datatracker.ietf.org/doc/html/draft-meunier-http-message-signatures-directory-01#name-request-with-http-signature).
93
+
94
+ </details>
95
+
96
+ &nbsp;
97
+
98
+ ## Authentication
99
+
100
+ > Turn any curl request into a signed, authenticated request.
52
101
 
53
102
  ```sh
54
- $ vestauth provider verify GET https://ping.vestauth.com/ping
103
+ > without vestauth
104
+ $ curl https://api.vestauth.com/whoami
105
+ {"error":{"status":400,"code":null,"message":"bad_request","help":null,"meta":null}}
106
+
107
+ > with vestauth
108
+ $ vestauth agent curl https://api.vestauth.com/whoami
109
+ {"uid":"agent-4b94ccd425e939fac5016b6b",...}
55
110
  ```
56
111
 
57
- More examples
112
+ <details><summary>learn more</summary><br>
58
113
 
59
- * Express.js
60
- * Next.js
61
- * Rails
62
- * ...
114
+ Vestauth autosigns each curl request – injecting valid signed headers according to the [web-bot-auth draft](https://datatracker.ietf.org/doc/html/draft-meunier-web-bot-auth-architecture). View these with the built-in `headers` primitive.
63
115
 
64
- ### List of current providers
116
+ ```
117
+ $ vestauth primitives headers GET https://api.vestauth.com/whoami --pp
118
+ {
119
+ "Signature": "sig1=:d4Id5SXhUExsf1XyruD8eBmlDtWzt/vezoCS+SKf0M8CxSkhKBtdHH7KkYyMN6E0hmxmNHsYus11u32nhvpWBQ==:",
120
+ "Signature-Input": "sig1=(\"@authority\");created=1770247189;keyid=\"B0u80Gw28W9U2Jl5t_EBiWeBajO2104kOYZ9Ikucl5I\";alg=\"ed25519\";expires=1770247489;nonce=\"NURxn28X7zyKJ9k5bHxuOyO5qdvF9L5s2qHmhTrGUzbwGSIoUCHmwSlwiiCRgTDGuum83yyWMHJU4jmrVI_XPg\";tag=\"web-bot-auth\"",
121
+ "Signature-Agent": "sig1=agent-4b94ccd425e939fac5016b6b.agents.vestauth.com"
122
+ }
123
+ ```
65
124
 
66
- * `dotenvx as2` – agentic secret storage
125
+ </details>
126
+
127
+ &nbsp;
128
+
129
+ ## Verification
130
+
131
+ > As a provider of agentic tools, authenticate agents through cryptographic verification.
132
+
133
+ ```sh
134
+
135
+ ```
67
136
 
68
137
  ## Advanced
69
138
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vestauth",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "auth for agents–from the creator of dotenvx",
5
5
  "keywords": [
6
6
  "vestauth"
@@ -2,37 +2,44 @@ const { logger } = require('./../../../shared/logger')
2
2
  const agent = require('./../../../lib/agent')
3
3
  const execute = require('./../../../lib/helpers/execute')
4
4
  const findUrl = require('./../../../lib/helpers/findUrl')
5
+ const catchAndLog = require('./../../../lib/helpers/catchAndLog')
5
6
 
6
7
  async function curl () {
7
- const commandArgs = this.args
8
- logger.debug(`process command [${commandArgs.join(' ')}]`)
9
-
10
- const options = this.opts()
11
- logger.debug(`options: ${JSON.stringify(options)}`)
12
-
13
- const httpMethod = 'GET'
14
- const url = findUrl(commandArgs)
15
- const headers = await agent.headers(httpMethod, url)
16
- const injected = [
17
- 'curl',
18
- '-H', `Signature: ${headers.Signature}`,
19
- '-H', `Signature-Input: ${headers['Signature-Input']}`,
20
- ...commandArgs
21
- ]
22
-
23
- const { stdout, exitCode } = await execute.execa(injected[0], injected.slice(1), {})
24
-
25
- if (exitCode !== 0) {
26
- logger.debug(`received exitCode ${exitCode}`)
27
- throw new Error(`Command exited with exit code ${exitCode}`)
8
+ try {
9
+ const commandArgs = this.args
10
+ logger.debug(`process command [${commandArgs.join(' ')}]`)
11
+
12
+ const options = this.opts()
13
+ logger.debug(`options: ${JSON.stringify(options)}`)
14
+
15
+ const httpMethod = 'GET'
16
+ const url = findUrl(commandArgs)
17
+ const headers = await agent.headers(httpMethod, url)
18
+ const injected = [
19
+ 'curl',
20
+ '-H', `Signature: ${headers.Signature}`,
21
+ '-H', `Signature-Input: ${headers['Signature-Input']}`,
22
+ '-H', `Signature-Agent: ${headers['Signature-Agent']}`,
23
+ ...commandArgs
24
+ ]
25
+
26
+ const { stdout, exitCode } = await execute.execa(injected[0], injected.slice(1), {})
27
+
28
+ if (exitCode !== 0) {
29
+ logger.debug(`received exitCode ${exitCode}`)
30
+ throw new Error(`Command exited with exit code ${exitCode}`)
31
+ }
32
+
33
+ let space = 0
34
+ if (options.prettyPrint) {
35
+ space = 2
36
+ }
37
+
38
+ console.log(JSON.stringify(JSON.parse(stdout), null, space))
39
+ } catch (error) {
40
+ catchAndLog(error)
41
+ process.exit(1)
28
42
  }
29
-
30
- let space = 0
31
- if (options.prettyPrint) {
32
- space = 2
33
- }
34
-
35
- console.log(JSON.stringify(JSON.parse(stdout), null, space))
36
43
  }
37
44
 
38
45
  module.exports = curl
@@ -1,13 +1,34 @@
1
1
  const { parseDictionary } = require('structured-headers')
2
2
  const Errors = require('./errors')
3
3
 
4
- // example: sig1=https://agent-9aa52a556ca85ee195866c0b.agents.vestauth.com
4
+ // example: sig1=agent-9aa52a556ca85ee195866c0b.agents.vestauth.com
5
5
  function parseSignatureAgentHeader (signatureAgentHeader) {
6
- const dictionary = parseDictionary(signatureAgentHeader)
6
+ if (Array.isArray(signatureAgentHeader)) {
7
+ signatureAgentHeader = signatureAgentHeader[0]
8
+ }
9
+ if (typeof signatureAgentHeader !== 'string' || signatureAgentHeader.length === 0) {
10
+ throw new Errors().invalidSignatureAgent()
11
+ }
12
+
13
+ let dictionary
14
+ try {
15
+ dictionary = parseDictionary(signatureAgentHeader)
16
+ } catch {
17
+ throw new Errors().invalidSignatureAgent()
18
+ }
7
19
  const entry = dictionary.entries().next()
8
20
  if (entry.done) throw new Errors().invalidSignatureAgent()
9
- const [key, innerlist] = entry.value
10
- const value = innerlist[0].value
21
+ const [key, member] = entry.value
22
+ let value
23
+ if (typeof member === 'string') {
24
+ value = member
25
+ } else if (member && typeof member === 'object' && 'value' in member) {
26
+ value = member.value
27
+ } else if (Array.isArray(member) && typeof member[0] === 'string') {
28
+ value = member[0]
29
+ } else if (Array.isArray(member) && member[0] && typeof member[0] === 'object' && 'value' in member[0]) {
30
+ value = member[0].value
31
+ }
11
32
  if (!value) throw new Errors().invalidSignatureAgent()
12
33
 
13
34
  return {
@@ -5,7 +5,7 @@ const verifyAgentFqdn = require('./verifyAgentFqdn')
5
5
  const verify = require('./verify')
6
6
 
7
7
  async function providerVerify (httpMethod, uri, headers = {}) {
8
- const signatureAgent = headers['Signature-Agent']
8
+ const signatureAgent = headers['Signature-Agent'] || headers['signature-agent'] // support either case (expressjs lowers headers)
9
9
  const { value } = parseSignatureAgentHeader(signatureAgent) // sig1=agent-1234.agents.vestauth.com
10
10
  const fqdn = value
11
11
  verifyAgentFqdn(fqdn)
@@ -6,8 +6,8 @@ const authorityMessage = require('./authorityMessage')
6
6
  const publicJwkObject = require('./publicJwkObject')
7
7
 
8
8
  function verify (httpMethod, uri, headers = {}, publicJwk) {
9
- const signature = headers.Signature
10
- const signatureInput = headers['Signature-Input']
9
+ const signature = headers.Signature || headers.signature
10
+ const signatureInput = headers['Signature-Input'] || headers['signature-input']
11
11
 
12
12
  const { values } = parseSignatureInputHeader(signatureInput)
13
13
  const { expires } = values