@countersig/verify 1.0.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.
Files changed (4) hide show
  1. package/README.md +92 -0
  2. package/index.d.ts +43 -0
  3. package/index.js +147 -0
  4. package/package.json +22 -0
package/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # @countersig/verify
2
+
3
+ Countersig A2A token verification library. Verify agent-to-agent authentication tokens issued by the Countersig platform.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @countersig/verify
9
+ ```
10
+
11
+ For remote verification (no shared secret), also install axios:
12
+
13
+ ```bash
14
+ npm install axios
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### Local Verification (with shared secret)
20
+
21
+ Fastest method — no network call required.
22
+
23
+ ```javascript
24
+ const { CountersigVerifier } = require('@countersig/verify');
25
+
26
+ const verifier = new CountersigVerifier({
27
+ secret: process.env.A2A_TOKEN_SECRET
28
+ });
29
+
30
+ const payload = verifier.verifyLocal(token);
31
+ console.log(payload.sub); // Agent ID
32
+ console.log(payload.caps); // Agent capabilities
33
+ console.log(payload.score); // BAGS reputation score
34
+ ```
35
+
36
+ ### Remote Verification (via Countersig API)
37
+
38
+ No shared secret needed — the Countersig API verifies the token server-side.
39
+
40
+ ```javascript
41
+ const { CountersigVerifier } = require('@countersig/verify');
42
+
43
+ const verifier = new CountersigVerifier({
44
+ apiUrl: 'https://api.countersig.com'
45
+ });
46
+
47
+ const payload = await verifier.verifyRemote(token);
48
+ console.log(payload.sub); // Agent ID
49
+ console.log(payload.name); // Agent name
50
+ ```
51
+
52
+ ### Auto-Detect Verification Method
53
+
54
+ Uses local verification when a secret is available, falls back to remote otherwise.
55
+
56
+ ```javascript
57
+ const verifier = new CountersigVerifier({
58
+ secret: process.env.A2A_TOKEN_SECRET, // optional
59
+ apiUrl: 'https://api.countersig.com' // optional
60
+ });
61
+
62
+ const payload = await verifier.verify(token);
63
+ ```
64
+
65
+ ### Inspect Token (no verification)
66
+
67
+ ```javascript
68
+ const decoded = verifier.decode(token);
69
+ console.log(decoded); // Raw payload — DO NOT trust for auth decisions
70
+ ```
71
+
72
+ ## Token Payload
73
+
74
+ A verified A2A token contains:
75
+
76
+ | Field | Type | Description |
77
+ | ------ | -------- | ---------------------------------- |
78
+ | `sub` | string | Agent ID |
79
+ | `type` | 'a2a' | Token type identifier |
80
+ | `name` | string | Agent display name |
81
+ | `pubkey` | string | Agent's public key |
82
+ | `chain` | string | Blockchain type (solana, ethereum) |
83
+ | `caps` | string[] | Agent capabilities |
84
+ | `score` | number | BAGS reputation score |
85
+ | `iss` | string | Issuer (countersig.com) |
86
+ | `aud` | string | Audience (countersig-a2a) |
87
+ | `iat` | number | Issued-at timestamp |
88
+ | `exp` | number | Expiration timestamp (60s from iat)|
89
+
90
+ ## License
91
+
92
+ MIT
package/index.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ export interface CountersigVerifierOptions {
2
+ /** PEM-encoded Ed25519 public key (SPKI format) for local verification */
3
+ publicKey?: string;
4
+ /** JWK-formatted Ed25519 public key for local verification */
5
+ jwk?: JsonWebKey;
6
+ /** Countersig API URL (default: https://api.countersig.com) */
7
+ apiUrl?: string;
8
+ /** @deprecated HMAC secret — migrate to Ed25519 public key or JWKS */
9
+ secret?: string;
10
+ }
11
+
12
+ export interface A2ATokenPayload {
13
+ sub: string;
14
+ type: 'a2a';
15
+ name: string;
16
+ pubkey: string;
17
+ chain: string;
18
+ caps: string[];
19
+ score: number;
20
+ iss: string;
21
+ aud: string;
22
+ iat: number;
23
+ exp: number;
24
+ }
25
+
26
+ export declare class CountersigVerifier {
27
+ constructor(options?: CountersigVerifierOptions);
28
+
29
+ /** Verify token locally using Ed25519 public key */
30
+ verifyLocal(token: string): Promise<A2ATokenPayload>;
31
+
32
+ /** Verify token using JWKS fetched from Countersig API */
33
+ verifyWithJWKS(token: string): Promise<A2ATokenPayload>;
34
+
35
+ /** Verify token via Countersig HTTP API */
36
+ verifyRemote(token: string): Promise<A2ATokenPayload>;
37
+
38
+ /** Auto-select best verification method */
39
+ verify(token: string): Promise<A2ATokenPayload>;
40
+
41
+ /** Decode token without verification */
42
+ decode(token: string): A2ATokenPayload;
43
+ }
package/index.js ADDED
@@ -0,0 +1,147 @@
1
+ /**
2
+ * @countersig/verify — A2A Token Verification SDK
3
+ *
4
+ * Verifies Countersig A2A tokens using Ed25519 asymmetric cryptography.
5
+ * No shared secret required — only the public key or JWKS endpoint.
6
+ */
7
+
8
+ let jose;
9
+ function getJose() {
10
+ if (!jose) {
11
+ try {
12
+ jose = require('jose');
13
+ } catch {
14
+ throw new Error('@countersig/verify requires the jose library. Run: npm install jose');
15
+ }
16
+ }
17
+ return jose;
18
+ }
19
+
20
+ class CountersigVerifier {
21
+ /**
22
+ * @param {Object} options
23
+ * @param {string} [options.publicKey] - PEM-encoded Ed25519 public key (SPKI format)
24
+ * @param {Object} [options.jwk] - JWK-formatted Ed25519 public key
25
+ * @param {string} [options.apiUrl] - Countersig API URL for remote/JWKS verification
26
+ * @param {string} [options.secret] - DEPRECATED: HMAC secret (backward compat, dev only)
27
+ */
28
+ constructor(options = {}) {
29
+ this.apiUrl = options.apiUrl || 'https://api.countersig.com';
30
+ this.issuer = 'countersig.com';
31
+ this.audience = 'countersig-a2a';
32
+ this._publicKeyPem = options.publicKey || null;
33
+ this._jwk = options.jwk || null;
34
+ this._secret = options.secret || null;
35
+ this._resolvedKey = null;
36
+ this._jwksSet = null;
37
+
38
+ if (this._secret) {
39
+ console.warn('[CountersigVerifier] HMAC secret verification is deprecated. Migrate to Ed25519 public key or JWKS.');
40
+ }
41
+ }
42
+
43
+ /** Resolve the public key for local verification */
44
+ async _getKey() {
45
+ if (this._resolvedKey) return this._resolvedKey;
46
+ const { importSPKI, importJWK } = getJose();
47
+ if (this._publicKeyPem) {
48
+ this._resolvedKey = await importSPKI(this._publicKeyPem, 'EdDSA');
49
+ } else if (this._jwk) {
50
+ this._resolvedKey = await importJWK(this._jwk, 'EdDSA');
51
+ }
52
+ return this._resolvedKey;
53
+ }
54
+
55
+ /**
56
+ * Verify token locally using Ed25519 public key.
57
+ * @param {string} token - JWT token string
58
+ * @returns {Promise<Object>} Decoded payload
59
+ */
60
+ async verifyLocal(token) {
61
+ const key = await this._getKey();
62
+ if (!key) throw new Error('No public key configured for local verification');
63
+ const { jwtVerify } = getJose();
64
+ const { payload } = await jwtVerify(token, key, {
65
+ issuer: this.issuer,
66
+ audience: this.audience,
67
+ });
68
+ return payload;
69
+ }
70
+
71
+ /**
72
+ * Verify token using JWKS fetched from the Countersig API.
73
+ * @param {string} token - JWT token string
74
+ * @returns {Promise<Object>} Decoded payload
75
+ */
76
+ async verifyWithJWKS(token) {
77
+ const { createRemoteJWKSet, jwtVerify } = getJose();
78
+ if (!this._jwksSet) {
79
+ this._jwksSet = createRemoteJWKSet(new URL(`${this.apiUrl}/.well-known/jwks.json`));
80
+ }
81
+ const { payload } = await jwtVerify(token, this._jwksSet, {
82
+ issuer: this.issuer,
83
+ audience: this.audience,
84
+ });
85
+ return payload;
86
+ }
87
+
88
+ /**
89
+ * Verify token via Countersig HTTP API (POST /agents/verify-token).
90
+ * @param {string} token - JWT token string
91
+ * @returns {Promise<Object>} Decoded payload
92
+ */
93
+ async verifyRemote(token) {
94
+ let axios;
95
+ try { axios = require('axios'); } catch {
96
+ throw new Error('axios is required for remote verification. Run: npm install axios');
97
+ }
98
+ const response = await axios.post(
99
+ `${this.apiUrl}/agents/verify-token`,
100
+ { token },
101
+ { timeout: 5000 }
102
+ );
103
+ if (!response.data?.valid) {
104
+ throw new Error(response.data?.error || 'Token verification failed');
105
+ }
106
+ return response.data.payload;
107
+ }
108
+
109
+ /**
110
+ * Auto-select best verification method:
111
+ * 1. Local (if public key provided)
112
+ * 2. JWKS (if apiUrl configured, fetches public key automatically)
113
+ * 3. Remote HTTP (fallback)
114
+ *
115
+ * DEPRECATED: HMAC secret fallback (if secret provided)
116
+ * @param {string} token - JWT token string
117
+ * @returns {Promise<Object>} Decoded payload
118
+ */
119
+ async verify(token) {
120
+ // Ed25519 local verification (preferred)
121
+ if (this._publicKeyPem || this._jwk) {
122
+ return this.verifyLocal(token);
123
+ }
124
+ // HMAC fallback (deprecated, dev only)
125
+ if (this._secret) {
126
+ const jwtLib = require('jsonwebtoken');
127
+ return jwtLib.verify(token, this._secret, {
128
+ issuer: this.issuer,
129
+ audience: this.audience,
130
+ });
131
+ }
132
+ // JWKS auto-fetch (recommended for production consumers)
133
+ return this.verifyWithJWKS(token);
134
+ }
135
+
136
+ /**
137
+ * Decode token without verification (for inspection only).
138
+ * @param {string} token - JWT token string
139
+ * @returns {Object} Decoded payload
140
+ */
141
+ decode(token) {
142
+ const { decodeJwt } = getJose();
143
+ return decodeJwt(token);
144
+ }
145
+ }
146
+
147
+ module.exports = { CountersigVerifier };
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@countersig/verify",
3
+ "version": "1.0.0",
4
+ "description": "Countersig A2A token verification library",
5
+ "main": "index.js",
6
+ "types": "index.d.ts",
7
+ "license": "MIT",
8
+ "keywords": ["countersig", "a2a", "agent", "verification", "nhi", "identity"],
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/RunTimeAdmin/AgentID-2.0-Public"
12
+ },
13
+ "dependencies": {
14
+ "jose": "^5.9.0"
15
+ },
16
+ "optionalDependencies": {
17
+ "jsonwebtoken": "^9.0.2"
18
+ },
19
+ "peerDependencies": {
20
+ "axios": "^1.6.0"
21
+ }
22
+ }