@opensyber/tokenforge 0.1.2 → 1.1.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/LICENSE.md +32 -0
- package/README.md +329 -52
- package/dist/adapters/astro.d.ts +64 -0
- package/dist/adapters/astro.d.ts.map +1 -0
- package/dist/adapters/astro.js +104 -0
- package/dist/adapters/astro.js.map +1 -0
- package/dist/adapters/cloud-v2-bridge.d.ts +8 -0
- package/dist/adapters/cloud-v2-bridge.d.ts.map +1 -0
- package/dist/adapters/cloud-v2-bridge.js +24 -0
- package/dist/adapters/cloud-v2-bridge.js.map +1 -0
- package/dist/adapters/express.d.ts +30 -2
- package/dist/adapters/express.d.ts.map +1 -1
- package/dist/adapters/express.js +65 -0
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/fastify.d.ts +32 -6
- package/dist/adapters/fastify.d.ts.map +1 -1
- package/dist/adapters/fastify.js +65 -0
- package/dist/adapters/fastify.js.map +1 -1
- package/dist/adapters/hono.d.ts +13 -1
- package/dist/adapters/hono.d.ts.map +1 -1
- package/dist/adapters/hono.js +14 -1
- package/dist/adapters/hono.js.map +1 -1
- package/dist/adapters/index.d.ts +5 -3
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +5 -3
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/nextjs.d.ts +31 -0
- package/dist/adapters/nextjs.d.ts.map +1 -1
- package/dist/adapters/nextjs.js +83 -30
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/sveltekit.d.ts +66 -0
- package/dist/adapters/sveltekit.d.ts.map +1 -0
- package/dist/adapters/sveltekit.js +101 -0
- package/dist/adapters/sveltekit.js.map +1 -0
- package/dist/client/action-signer.d.ts +53 -0
- package/dist/client/action-signer.d.ts.map +1 -0
- package/dist/client/action-signer.js +48 -0
- package/dist/client/action-signer.js.map +1 -0
- package/dist/client/binding.d.ts +24 -7
- package/dist/client/binding.d.ts.map +1 -1
- package/dist/client/binding.js +17 -6
- package/dist/client/binding.js.map +1 -1
- package/dist/client/cloud-device.d.ts +54 -0
- package/dist/client/cloud-device.d.ts.map +1 -0
- package/dist/client/cloud-device.js +301 -0
- package/dist/client/cloud-device.js.map +1 -0
- package/dist/client/crypto.d.ts.map +1 -1
- package/dist/client/crypto.js.map +1 -1
- package/dist/client/index.d.ts +14 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +30 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/interceptor.d.ts.map +1 -1
- package/dist/client/interceptor.js +27 -3
- package/dist/client/interceptor.js.map +1 -1
- package/dist/client/signer.d.ts +40 -3
- package/dist/client/signer.d.ts.map +1 -1
- package/dist/client/signer.js +56 -5
- package/dist/client/signer.js.map +1 -1
- package/dist/client/storage.d.ts.map +1 -1
- package/dist/client/storage.js.map +1 -1
- package/dist/client/webauthn.d.ts +45 -0
- package/dist/client/webauthn.d.ts.map +1 -0
- package/dist/client/webauthn.js +118 -0
- package/dist/client/webauthn.js.map +1 -0
- package/dist/protocol/v2.d.ts +23 -0
- package/dist/protocol/v2.d.ts.map +1 -0
- package/dist/protocol/v2.js +157 -0
- package/dist/protocol/v2.js.map +1 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react/provider.d.ts.map +1 -1
- package/dist/react/provider.js.map +1 -1
- package/dist/server/action-verify.d.ts +56 -0
- package/dist/server/action-verify.d.ts.map +1 -0
- package/dist/server/action-verify.js +47 -0
- package/dist/server/action-verify.js.map +1 -0
- package/dist/server/activity-histogram.d.ts +47 -0
- package/dist/server/activity-histogram.d.ts.map +1 -0
- package/dist/server/activity-histogram.js +76 -0
- package/dist/server/activity-histogram.js.map +1 -0
- package/dist/server/aitm-heuristics.d.ts +57 -0
- package/dist/server/aitm-heuristics.d.ts.map +1 -0
- package/dist/server/aitm-heuristics.js +120 -0
- package/dist/server/aitm-heuristics.js.map +1 -0
- package/dist/server/bind-with-id-token.d.ts +55 -0
- package/dist/server/bind-with-id-token.d.ts.map +1 -0
- package/dist/server/bind-with-id-token.js +70 -0
- package/dist/server/bind-with-id-token.js.map +1 -0
- package/dist/server/bound-cookie.d.ts +39 -0
- package/dist/server/bound-cookie.d.ts.map +1 -0
- package/dist/server/bound-cookie.js +59 -0
- package/dist/server/bound-cookie.js.map +1 -0
- package/dist/server/cbor.d.ts +20 -0
- package/dist/server/cbor.d.ts.map +1 -0
- package/dist/server/cbor.js +110 -0
- package/dist/server/cbor.js.map +1 -0
- package/dist/server/cloud-bind.d.ts +42 -0
- package/dist/server/cloud-bind.d.ts.map +1 -0
- package/dist/server/cloud-bind.js +387 -0
- package/dist/server/cloud-bind.js.map +1 -0
- package/dist/server/cloud-middleware.d.ts +46 -0
- package/dist/server/cloud-middleware.d.ts.map +1 -0
- package/dist/server/cloud-middleware.js +344 -0
- package/dist/server/cloud-middleware.js.map +1 -0
- package/dist/server/cloud-verify.d.ts +30 -0
- package/dist/server/cloud-verify.d.ts.map +1 -0
- package/dist/server/cloud-verify.js +206 -0
- package/dist/server/cloud-verify.js.map +1 -0
- package/dist/server/dbsc-challenge.d.ts +51 -0
- package/dist/server/dbsc-challenge.d.ts.map +1 -0
- package/dist/server/dbsc-challenge.js +78 -0
- package/dist/server/dbsc-challenge.js.map +1 -0
- package/dist/server/dbsc-endpoint.d.ts +20 -0
- package/dist/server/dbsc-endpoint.d.ts.map +1 -0
- package/dist/server/dbsc-endpoint.js +85 -0
- package/dist/server/dbsc-endpoint.js.map +1 -0
- package/dist/server/dbsc-verify.d.ts +32 -0
- package/dist/server/dbsc-verify.d.ts.map +1 -0
- package/dist/server/dbsc-verify.js +65 -0
- package/dist/server/dbsc-verify.js.map +1 -0
- package/dist/server/identity-profile.d.ts +18 -0
- package/dist/server/identity-profile.d.ts.map +1 -0
- package/dist/server/identity-profile.js +113 -0
- package/dist/server/identity-profile.js.map +1 -0
- package/dist/server/index.d.ts +12 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +7 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/jws-verify.d.ts +46 -0
- package/dist/server/jws-verify.d.ts.map +1 -0
- package/dist/server/jws-verify.js +64 -0
- package/dist/server/jws-verify.js.map +1 -0
- package/dist/server/middleware.d.ts +24 -0
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +87 -20
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/oidc-verify.d.ts +71 -0
- package/dist/server/oidc-verify.d.ts.map +1 -0
- package/dist/server/oidc-verify.js +115 -0
- package/dist/server/oidc-verify.js.map +1 -0
- package/dist/server/policy.d.ts +47 -0
- package/dist/server/policy.d.ts.map +1 -0
- package/dist/server/policy.js +84 -0
- package/dist/server/policy.js.map +1 -0
- package/dist/server/step-up-policy.d.ts +36 -0
- package/dist/server/step-up-policy.d.ts.map +1 -0
- package/dist/server/step-up-policy.js +101 -0
- package/dist/server/step-up-policy.js.map +1 -0
- package/dist/server/storage/index.d.ts +3 -0
- package/dist/server/storage/index.d.ts.map +1 -0
- package/dist/server/storage/index.js +2 -0
- package/dist/server/storage/index.js.map +1 -0
- package/dist/server/storage/interface.d.ts +73 -0
- package/dist/server/storage/interface.d.ts.map +1 -0
- package/dist/server/storage/interface.js +2 -0
- package/dist/server/storage/interface.js.map +1 -0
- package/dist/server/storage/memory.d.ts +50 -0
- package/dist/server/storage/memory.d.ts.map +1 -0
- package/dist/server/storage/memory.js +121 -0
- package/dist/server/storage/memory.js.map +1 -0
- package/dist/server/webauthn-verify.d.ts +41 -0
- package/dist/server/webauthn-verify.d.ts.map +1 -0
- package/dist/server/webauthn-verify.js +175 -0
- package/dist/server/webauthn-verify.js.map +1 -0
- package/dist/server/webhooks.d.ts +42 -0
- package/dist/server/webhooks.d.ts.map +1 -0
- package/dist/server/webhooks.js +77 -0
- package/dist/server/webhooks.js.map +1 -0
- package/dist/shared/action-hash.d.ts +23 -0
- package/dist/shared/action-hash.d.ts.map +1 -0
- package/dist/shared/action-hash.js +35 -0
- package/dist/shared/action-hash.js.map +1 -0
- package/dist/shared/identity.d.ts +45 -0
- package/dist/shared/identity.d.ts.map +1 -0
- package/dist/shared/identity.js +176 -0
- package/dist/shared/identity.js.map +1 -0
- package/dist/shared/types-internal.d.ts.map +1 -1
- package/dist/shared/types-internal.js.map +1 -1
- package/dist/shared/types.d.ts +49 -2
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +1 -0
- package/dist/shared/types.js.map +1 -1
- package/package.json +31 -33
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhook receiver helpers for TokenForge cloud deliveries.
|
|
3
|
+
*
|
|
4
|
+
* Every delivery carries three relevant headers:
|
|
5
|
+
* X-TF-Signature: "v1,<hex>" (one or more, space-separated during rotation)
|
|
6
|
+
* X-TF-Timestamp: ISO-8601 string — the moment dispatcher built the payload
|
|
7
|
+
* X-TF-Delivery-Id: UUID — per-attempt id, use for idempotency
|
|
8
|
+
*
|
|
9
|
+
* The signed string is `${timestamp}.${rawBody}` (no whitespace). During
|
|
10
|
+
* rotation, the dispatcher may send two `v1,<hex>` signatures — accept if
|
|
11
|
+
* either matches.
|
|
12
|
+
*
|
|
13
|
+
* Example (Node.js, Hono):
|
|
14
|
+
*
|
|
15
|
+
* import { verifyWebhookSignature } from '@opensyber/tokenforge/webhooks';
|
|
16
|
+
*
|
|
17
|
+
* app.post('/webhooks/tokenforge', async (c) => {
|
|
18
|
+
* const rawBody = await c.req.text();
|
|
19
|
+
* const ok = await verifyWebhookSignature({
|
|
20
|
+
* body: rawBody,
|
|
21
|
+
* signatureHeader: c.req.header('X-TF-Signature') ?? '',
|
|
22
|
+
* timestampHeader: c.req.header('X-TF-Timestamp') ?? '',
|
|
23
|
+
* secret: c.env.TOKENFORGE_WEBHOOK_SECRET,
|
|
24
|
+
* });
|
|
25
|
+
* if (!ok) return c.json({ error: 'bad_signature' }, 401);
|
|
26
|
+
* const event = JSON.parse(rawBody);
|
|
27
|
+
* // handle event.event, event.data ...
|
|
28
|
+
* return c.json({ received: true });
|
|
29
|
+
* });
|
|
30
|
+
*/
|
|
31
|
+
export interface VerifyOptions {
|
|
32
|
+
body: string;
|
|
33
|
+
signatureHeader: string;
|
|
34
|
+
timestampHeader: string;
|
|
35
|
+
secret: string;
|
|
36
|
+
/** Max allowed clock skew in ms. Default 300000 (5 min). */
|
|
37
|
+
toleranceMs?: number;
|
|
38
|
+
/** Accept requests with missing timestamp (legacy). Default false. */
|
|
39
|
+
allowMissingTimestamp?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export declare function verifyWebhookSignature(opts: VerifyOptions): Promise<boolean>;
|
|
42
|
+
//# sourceMappingURL=webhooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.d.ts","sourceRoot":"../src/","sources":["server/webhooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAyBlF"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhook receiver helpers for TokenForge cloud deliveries.
|
|
3
|
+
*
|
|
4
|
+
* Every delivery carries three relevant headers:
|
|
5
|
+
* X-TF-Signature: "v1,<hex>" (one or more, space-separated during rotation)
|
|
6
|
+
* X-TF-Timestamp: ISO-8601 string — the moment dispatcher built the payload
|
|
7
|
+
* X-TF-Delivery-Id: UUID — per-attempt id, use for idempotency
|
|
8
|
+
*
|
|
9
|
+
* The signed string is `${timestamp}.${rawBody}` (no whitespace). During
|
|
10
|
+
* rotation, the dispatcher may send two `v1,<hex>` signatures — accept if
|
|
11
|
+
* either matches.
|
|
12
|
+
*
|
|
13
|
+
* Example (Node.js, Hono):
|
|
14
|
+
*
|
|
15
|
+
* import { verifyWebhookSignature } from '@opensyber/tokenforge/webhooks';
|
|
16
|
+
*
|
|
17
|
+
* app.post('/webhooks/tokenforge', async (c) => {
|
|
18
|
+
* const rawBody = await c.req.text();
|
|
19
|
+
* const ok = await verifyWebhookSignature({
|
|
20
|
+
* body: rawBody,
|
|
21
|
+
* signatureHeader: c.req.header('X-TF-Signature') ?? '',
|
|
22
|
+
* timestampHeader: c.req.header('X-TF-Timestamp') ?? '',
|
|
23
|
+
* secret: c.env.TOKENFORGE_WEBHOOK_SECRET,
|
|
24
|
+
* });
|
|
25
|
+
* if (!ok) return c.json({ error: 'bad_signature' }, 401);
|
|
26
|
+
* const event = JSON.parse(rawBody);
|
|
27
|
+
* // handle event.event, event.data ...
|
|
28
|
+
* return c.json({ received: true });
|
|
29
|
+
* });
|
|
30
|
+
*/
|
|
31
|
+
export async function verifyWebhookSignature(opts) {
|
|
32
|
+
const { body, signatureHeader, timestampHeader, secret } = opts;
|
|
33
|
+
const tolerance = opts.toleranceMs ?? 5 * 60_000;
|
|
34
|
+
if (!signatureHeader || !secret)
|
|
35
|
+
return false;
|
|
36
|
+
if (!timestampHeader) {
|
|
37
|
+
if (!opts.allowMissingTimestamp)
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const ts = Date.parse(timestampHeader);
|
|
42
|
+
if (Number.isNaN(ts))
|
|
43
|
+
return false;
|
|
44
|
+
if (Math.abs(Date.now() - ts) > tolerance)
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
const signedString = timestampHeader ? `${timestampHeader}.${body}` : body;
|
|
48
|
+
const expected = await hmacSha256Hex(secret, signedString);
|
|
49
|
+
// Signature header is space-separated list of "v1,<hex>" entries.
|
|
50
|
+
const entries = signatureHeader.split(/\s+/).filter(Boolean);
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
const [version, hex] = entry.split(',');
|
|
53
|
+
if (version !== 'v1' || !hex)
|
|
54
|
+
continue;
|
|
55
|
+
if (timingSafeEqual(hex.toLowerCase(), expected))
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
function timingSafeEqual(a, b) {
|
|
61
|
+
if (a.length !== b.length)
|
|
62
|
+
return false;
|
|
63
|
+
let diff = 0;
|
|
64
|
+
for (let i = 0; i < a.length; i++)
|
|
65
|
+
diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
66
|
+
return diff === 0;
|
|
67
|
+
}
|
|
68
|
+
async function hmacSha256Hex(secret, data) {
|
|
69
|
+
const key = await crypto.subtle.importKey('raw', new TextEncoder().encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
70
|
+
const sig = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(data));
|
|
71
|
+
const bytes = new Uint8Array(sig);
|
|
72
|
+
let hex = '';
|
|
73
|
+
for (let i = 0; i < bytes.length; i++)
|
|
74
|
+
hex += bytes[i].toString(16).padStart(2, '0');
|
|
75
|
+
return hex;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=webhooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.js","sourceRoot":"../src/","sources":["server/webhooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared canonicalization + hash helper for action signing.
|
|
3
|
+
*
|
|
4
|
+
* Client (`client/action-signer.ts`) and server
|
|
5
|
+
* (`server/action-verify.ts`) MUST agree on these byte-for-byte;
|
|
6
|
+
* sharing this file is the simplest enforcement.
|
|
7
|
+
*/
|
|
8
|
+
export interface ActionLikePayload {
|
|
9
|
+
action: string;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Stable JSON serialization — sorts top-level keys so `{a:1,b:2}` and
|
|
14
|
+
* `{b:2,a:1}` produce the same string. JS object literals preserve
|
|
15
|
+
* insertion order, so without this two semantically-identical
|
|
16
|
+
* payloads from different code paths would hash differently and the
|
|
17
|
+
* server would reject one of them as a tamper.
|
|
18
|
+
*/
|
|
19
|
+
export declare function canonicalizeAction(payload: Record<string, unknown>): string;
|
|
20
|
+
export declare function sha256B64Url(input: string): Promise<string>;
|
|
21
|
+
export declare function hashActionPayload(payload: Record<string, unknown>): Promise<string>;
|
|
22
|
+
export declare function b64UrlEncodeBytes(bytes: Uint8Array): string;
|
|
23
|
+
//# sourceMappingURL=action-hash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-hash.d.ts","sourceRoot":"../src/","sources":["shared/action-hash.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAK3E;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGjE;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAEzF;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAI3D"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared canonicalization + hash helper for action signing.
|
|
3
|
+
*
|
|
4
|
+
* Client (`client/action-signer.ts`) and server
|
|
5
|
+
* (`server/action-verify.ts`) MUST agree on these byte-for-byte;
|
|
6
|
+
* sharing this file is the simplest enforcement.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Stable JSON serialization — sorts top-level keys so `{a:1,b:2}` and
|
|
10
|
+
* `{b:2,a:1}` produce the same string. JS object literals preserve
|
|
11
|
+
* insertion order, so without this two semantically-identical
|
|
12
|
+
* payloads from different code paths would hash differently and the
|
|
13
|
+
* server would reject one of them as a tamper.
|
|
14
|
+
*/
|
|
15
|
+
export function canonicalizeAction(payload) {
|
|
16
|
+
const keys = Object.keys(payload).sort();
|
|
17
|
+
const ordered = {};
|
|
18
|
+
for (const k of keys)
|
|
19
|
+
ordered[k] = payload[k];
|
|
20
|
+
return JSON.stringify(ordered);
|
|
21
|
+
}
|
|
22
|
+
export async function sha256B64Url(input) {
|
|
23
|
+
const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(input));
|
|
24
|
+
return b64UrlEncodeBytes(new Uint8Array(buf));
|
|
25
|
+
}
|
|
26
|
+
export async function hashActionPayload(payload) {
|
|
27
|
+
return sha256B64Url(canonicalizeAction(payload));
|
|
28
|
+
}
|
|
29
|
+
export function b64UrlEncodeBytes(bytes) {
|
|
30
|
+
let bin = '';
|
|
31
|
+
for (let i = 0; i < bytes.length; i++)
|
|
32
|
+
bin += String.fromCharCode(bytes[i]);
|
|
33
|
+
return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=action-hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-hash.js","sourceRoot":"../src/","sources":["shared/action-hash.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAgC;IACjE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACzC,MAAM,OAAO,GAA4B,EAAE,CAAC;IAC5C,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9C,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAa;IAC9C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACnF,OAAO,iBAAiB,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAgC;IACtE,OAAO,YAAY,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAiB;IACjD,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,GAAG,IAAI,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;IAC7E,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC9E,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Version marker for the canonical Cloud v2 bind identity envelope. */
|
|
2
|
+
export declare const TOKENFORGE_IDENTITY_PROTOCOL: "tf-identity-v1";
|
|
3
|
+
/** Assurance is assigned by TokenForge after evaluating trusted evidence. */
|
|
4
|
+
export type TokenForgeIdentityAssurance = 'verified' | 'attested' | 'declared' | 'derived';
|
|
5
|
+
/** Optional display metadata supplied by an authenticated consumer backend. */
|
|
6
|
+
export interface TokenForgeIdentityProfile {
|
|
7
|
+
displayName?: string;
|
|
8
|
+
email?: string;
|
|
9
|
+
}
|
|
10
|
+
export type TokenForgeIdentityProfileField = 'displayName' | 'email';
|
|
11
|
+
/**
|
|
12
|
+
* Identity evidence attached to a Cloud v2 bind by trusted server code.
|
|
13
|
+
* The envelope intentionally has no caller-controlled assurance field.
|
|
14
|
+
*/
|
|
15
|
+
export interface TokenForgeIdentity {
|
|
16
|
+
protocol: typeof TOKENFORGE_IDENTITY_PROTOCOL;
|
|
17
|
+
externalUserRef: string;
|
|
18
|
+
externalUserRefVersion?: string;
|
|
19
|
+
profile?: TokenForgeIdentityProfile;
|
|
20
|
+
/** Explicitly delete stored display metadata; omission preserves prior values. */
|
|
21
|
+
clearProfile?: TokenForgeIdentityProfileField[];
|
|
22
|
+
idToken?: string;
|
|
23
|
+
workforceAppId?: string;
|
|
24
|
+
userIdSource?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface DeriveExternalUserRefInput {
|
|
27
|
+
/** Dedicated project correlation secret. Must contain at least 32 bytes. */
|
|
28
|
+
correlationSecret: Uint8Array;
|
|
29
|
+
projectId: string;
|
|
30
|
+
canonicalUserId: string;
|
|
31
|
+
/** Stable identifier for the active correlation key. Defaults to `v1`. */
|
|
32
|
+
version?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface DerivedExternalUserRef {
|
|
35
|
+
externalUserRef: string;
|
|
36
|
+
externalUserRefVersion: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Derive a non-reversible, project-scoped user reference with HMAC-SHA-256.
|
|
40
|
+
* The dedicated secret must remain server-side and distinct from API keys.
|
|
41
|
+
*/
|
|
42
|
+
export declare function deriveTokenForgeExternalUserRef(input: DeriveExternalUserRefInput): Promise<DerivedExternalUserRef>;
|
|
43
|
+
/** Parse and validate an untrusted Cloud v2 identity envelope. */
|
|
44
|
+
export declare function validateTokenForgeIdentity(input: unknown): TokenForgeIdentity;
|
|
45
|
+
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"../src/","sources":["shared/identity.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,eAAO,MAAM,4BAA4B,EAAG,gBAAyB,CAAC;AAqBtE,6EAA6E;AAC7E,MAAM,MAAM,2BAA2B,GACnC,UAAU,GACV,UAAU,GACV,UAAU,GACV,SAAS,CAAC;AAEd,+EAA+E;AAC/E,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,8BAA8B,GAAG,aAAa,GAAG,OAAO,CAAC;AAErE;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,OAAO,4BAA4B,CAAC;IAC9C,eAAe,EAAE,MAAM,CAAC;IACxB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,OAAO,CAAC,EAAE,yBAAyB,CAAC;IACpC,kFAAkF;IAClF,YAAY,CAAC,EAAE,8BAA8B,EAAE,CAAC;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,0BAA0B;IACzC,4EAA4E;IAC5E,iBAAiB,EAAE,UAAU,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,eAAe,EAAE,MAAM,CAAC;IACxB,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAED;;;GAGG;AACH,wBAAsB,+BAA+B,CACnD,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,sBAAsB,CAAC,CAwCjC;AAED,kEAAkE;AAClE,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,CAsD7E"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/** Version marker for the canonical Cloud v2 bind identity envelope. */
|
|
2
|
+
export const TOKENFORGE_IDENTITY_PROTOCOL = 'tf-identity-v1';
|
|
3
|
+
const EXTERNAL_USER_REF_PATTERN = /^[A-Za-z0-9_-]{43}$/;
|
|
4
|
+
const EXTERNAL_USER_REF_VERSION_PATTERN = /^[A-Za-z0-9._-]{1,32}$/;
|
|
5
|
+
const PROJECT_ID_PATTERN = /^[A-Za-z0-9_-]{8,256}$/;
|
|
6
|
+
const SOURCE_PATTERN = /^[A-Za-z0-9._:-]{1,64}$/;
|
|
7
|
+
const WORKFORCE_APP_ID_PATTERN = /^[A-Za-z0-9._:/-]{1,256}$/;
|
|
8
|
+
const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+$/;
|
|
9
|
+
const IDENTITY_KEYS = new Set([
|
|
10
|
+
'protocol',
|
|
11
|
+
'externalUserRef',
|
|
12
|
+
'externalUserRefVersion',
|
|
13
|
+
'profile',
|
|
14
|
+
'clearProfile',
|
|
15
|
+
'idToken',
|
|
16
|
+
'workforceAppId',
|
|
17
|
+
'userIdSource',
|
|
18
|
+
]);
|
|
19
|
+
const PROFILE_KEYS = new Set(['displayName', 'email']);
|
|
20
|
+
const PROFILE_FIELD_KEYS = new Set(['displayName', 'email']);
|
|
21
|
+
/**
|
|
22
|
+
* Derive a non-reversible, project-scoped user reference with HMAC-SHA-256.
|
|
23
|
+
* The dedicated secret must remain server-side and distinct from API keys.
|
|
24
|
+
*/
|
|
25
|
+
export async function deriveTokenForgeExternalUserRef(input) {
|
|
26
|
+
const version = input.version ?? 'v1';
|
|
27
|
+
if (!(input.correlationSecret instanceof Uint8Array) || input.correlationSecret.byteLength < 32) {
|
|
28
|
+
throw new Error('TokenForge correlation secret must contain at least 32 bytes');
|
|
29
|
+
}
|
|
30
|
+
if (!PROJECT_ID_PATTERN.test(input.projectId)) {
|
|
31
|
+
throw new Error('TokenForge project ID is invalid');
|
|
32
|
+
}
|
|
33
|
+
if (typeof input.canonicalUserId !== 'string' ||
|
|
34
|
+
input.canonicalUserId.length < 1 ||
|
|
35
|
+
input.canonicalUserId.length > 1024 ||
|
|
36
|
+
input.canonicalUserId !== input.canonicalUserId.trim() ||
|
|
37
|
+
containsControlCharacter(input.canonicalUserId)) {
|
|
38
|
+
throw new Error('TokenForge canonical user ID is invalid');
|
|
39
|
+
}
|
|
40
|
+
if (!EXTERNAL_USER_REF_VERSION_PATTERN.test(version)) {
|
|
41
|
+
throw new Error('TokenForge external user reference version is invalid');
|
|
42
|
+
}
|
|
43
|
+
if (!globalThis.crypto?.subtle) {
|
|
44
|
+
throw new Error('TokenForge correlation requires Web Crypto');
|
|
45
|
+
}
|
|
46
|
+
const key = await globalThis.crypto.subtle.importKey('raw', new Uint8Array(input.correlationSecret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
47
|
+
const message = new TextEncoder().encode(`tokenforge:user:v1\0${input.projectId}\0${input.canonicalUserId}`);
|
|
48
|
+
const digest = await globalThis.crypto.subtle.sign('HMAC', key, message);
|
|
49
|
+
return {
|
|
50
|
+
externalUserRef: base64Url(new Uint8Array(digest)),
|
|
51
|
+
externalUserRefVersion: version,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** Parse and validate an untrusted Cloud v2 identity envelope. */
|
|
55
|
+
export function validateTokenForgeIdentity(input) {
|
|
56
|
+
const identity = requireRecord(input, 'TokenForge identity');
|
|
57
|
+
rejectUnknownKeys(identity, IDENTITY_KEYS, 'TokenForge identity');
|
|
58
|
+
if (identity.protocol !== TOKENFORGE_IDENTITY_PROTOCOL) {
|
|
59
|
+
throw new Error('Unsupported TokenForge identity protocol');
|
|
60
|
+
}
|
|
61
|
+
if (typeof identity.externalUserRef !== 'string' || !EXTERNAL_USER_REF_PATTERN.test(identity.externalUserRef)) {
|
|
62
|
+
throw new Error('TokenForge external user reference is invalid');
|
|
63
|
+
}
|
|
64
|
+
const output = {
|
|
65
|
+
protocol: TOKENFORGE_IDENTITY_PROTOCOL,
|
|
66
|
+
externalUserRef: identity.externalUserRef,
|
|
67
|
+
};
|
|
68
|
+
if (identity.externalUserRefVersion !== undefined) {
|
|
69
|
+
if (typeof identity.externalUserRefVersion !== 'string' ||
|
|
70
|
+
!EXTERNAL_USER_REF_VERSION_PATTERN.test(identity.externalUserRefVersion)) {
|
|
71
|
+
throw new Error('TokenForge external user reference version is invalid');
|
|
72
|
+
}
|
|
73
|
+
output.externalUserRefVersion = identity.externalUserRefVersion;
|
|
74
|
+
}
|
|
75
|
+
if (identity.profile !== undefined) {
|
|
76
|
+
output.profile = validateProfile(identity.profile);
|
|
77
|
+
}
|
|
78
|
+
if (identity.clearProfile !== undefined) {
|
|
79
|
+
output.clearProfile = validateClearProfile(identity.clearProfile);
|
|
80
|
+
for (const field of output.clearProfile) {
|
|
81
|
+
if (output.profile?.[field] !== undefined) {
|
|
82
|
+
throw new Error(`TokenForge identity cannot set and clear ${field}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (identity.idToken !== undefined) {
|
|
87
|
+
output.idToken = requireBoundedString(identity.idToken, 'TokenForge ID token', 16_384);
|
|
88
|
+
}
|
|
89
|
+
if (identity.workforceAppId !== undefined) {
|
|
90
|
+
if (typeof identity.workforceAppId !== 'string' || !WORKFORCE_APP_ID_PATTERN.test(identity.workforceAppId)) {
|
|
91
|
+
throw new Error('TokenForge workforce application ID is invalid');
|
|
92
|
+
}
|
|
93
|
+
output.workforceAppId = identity.workforceAppId;
|
|
94
|
+
}
|
|
95
|
+
if (identity.userIdSource !== undefined) {
|
|
96
|
+
if (typeof identity.userIdSource !== 'string' || !SOURCE_PATTERN.test(identity.userIdSource)) {
|
|
97
|
+
throw new Error('TokenForge user ID source is invalid');
|
|
98
|
+
}
|
|
99
|
+
output.userIdSource = identity.userIdSource;
|
|
100
|
+
}
|
|
101
|
+
return output;
|
|
102
|
+
}
|
|
103
|
+
function validateClearProfile(input) {
|
|
104
|
+
if (!Array.isArray(input) || input.length < 1 || input.length > PROFILE_FIELD_KEYS.size) {
|
|
105
|
+
throw new Error('TokenForge clearProfile is invalid');
|
|
106
|
+
}
|
|
107
|
+
const fields = input.map((field) => {
|
|
108
|
+
if (typeof field !== 'string' || !PROFILE_FIELD_KEYS.has(field)) {
|
|
109
|
+
throw new Error('TokenForge clearProfile is invalid');
|
|
110
|
+
}
|
|
111
|
+
return field;
|
|
112
|
+
});
|
|
113
|
+
if (new Set(fields).size !== fields.length) {
|
|
114
|
+
throw new Error('TokenForge clearProfile contains duplicate fields');
|
|
115
|
+
}
|
|
116
|
+
return fields;
|
|
117
|
+
}
|
|
118
|
+
function validateProfile(input) {
|
|
119
|
+
const profile = requireRecord(input, 'TokenForge identity profile');
|
|
120
|
+
rejectUnknownKeys(profile, PROFILE_KEYS, 'TokenForge identity profile');
|
|
121
|
+
const output = {};
|
|
122
|
+
if (profile.displayName !== undefined) {
|
|
123
|
+
const displayName = requireBoundedString(profile.displayName, 'TokenForge display name', 200);
|
|
124
|
+
if (containsControlCharacter(displayName)) {
|
|
125
|
+
throw new Error('TokenForge display name contains control characters');
|
|
126
|
+
}
|
|
127
|
+
output.displayName = displayName;
|
|
128
|
+
}
|
|
129
|
+
if (profile.email !== undefined) {
|
|
130
|
+
const email = requireBoundedString(profile.email, 'TokenForge email', 254);
|
|
131
|
+
if (containsControlCharacter(email) || !EMAIL_PATTERN.test(email)) {
|
|
132
|
+
throw new Error('TokenForge email is invalid');
|
|
133
|
+
}
|
|
134
|
+
output.email = email;
|
|
135
|
+
}
|
|
136
|
+
if (output.displayName === undefined && output.email === undefined) {
|
|
137
|
+
throw new Error('TokenForge identity profile must contain displayName or email');
|
|
138
|
+
}
|
|
139
|
+
return output;
|
|
140
|
+
}
|
|
141
|
+
function containsControlCharacter(value) {
|
|
142
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
143
|
+
const code = value.charCodeAt(index);
|
|
144
|
+
if (code <= 0x1f || code === 0x7f)
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
function requireRecord(input, label) {
|
|
150
|
+
if (typeof input !== 'object' || input === null || Array.isArray(input)) {
|
|
151
|
+
throw new Error(`${label} must be an object`);
|
|
152
|
+
}
|
|
153
|
+
return input;
|
|
154
|
+
}
|
|
155
|
+
function rejectUnknownKeys(input, allowed, label) {
|
|
156
|
+
for (const key of Object.keys(input)) {
|
|
157
|
+
if (!allowed.has(key))
|
|
158
|
+
throw new Error(`${label} contains unsupported field: ${key}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function requireBoundedString(input, label, maxLength) {
|
|
162
|
+
if (typeof input !== 'string' ||
|
|
163
|
+
input.length < 1 ||
|
|
164
|
+
input.length > maxLength ||
|
|
165
|
+
input !== input.trim()) {
|
|
166
|
+
throw new Error(`${label} is invalid`);
|
|
167
|
+
}
|
|
168
|
+
return input;
|
|
169
|
+
}
|
|
170
|
+
function base64Url(bytes) {
|
|
171
|
+
let binary = '';
|
|
172
|
+
for (const byte of bytes)
|
|
173
|
+
binary += String.fromCharCode(byte);
|
|
174
|
+
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"../src/","sources":["shared/identity.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types-internal.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"types-internal.d.ts","sourceRoot":"../src/","sources":["shared/types-internal.ts"],"names":[],"mappings":"AAGA,qCAAqC;AACrC,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;IACvD,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,IAAI,CAAC;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,+CAA+C;AAC/C,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qCAAqC;AACrC,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,aAAa,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qCAAqC;AACrC,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,UAAU,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,mCAAmC;AACnC,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,uCAAuC;AACvC,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,iCAAiC;AACjC,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;CAC1C;AAED,kCAAkC;AAClC,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,iCAAiC;AACjC,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,kCAAkC;AAClC,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types-internal.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"types-internal.js","sourceRoot":"../src/","sources":["shared/types-internal.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,sEAAsE"}
|
package/dist/shared/types.d.ts
CHANGED
|
@@ -16,12 +16,26 @@ export interface TokenForgeConfig {
|
|
|
16
16
|
nonce?: string;
|
|
17
17
|
timestamp?: string;
|
|
18
18
|
deviceId?: string;
|
|
19
|
+
sessionId?: string;
|
|
20
|
+
version?: string;
|
|
21
|
+
bodyHash?: string;
|
|
19
22
|
};
|
|
20
23
|
/** Enable automatic fetch interception (default: true) */
|
|
21
24
|
autoIntercept?: boolean;
|
|
22
25
|
/** Paths to skip (no signing needed) */
|
|
23
26
|
skipPaths?: string[];
|
|
24
27
|
}
|
|
28
|
+
export { TOKENFORGE_IDENTITY_PROTOCOL, deriveTokenForgeExternalUserRef, validateTokenForgeIdentity, } from './identity.js';
|
|
29
|
+
export type { DerivedExternalUserRef, DeriveExternalUserRefInput, TokenForgeIdentity, TokenForgeIdentityAssurance, TokenForgeIdentityProfile, } from './identity.js';
|
|
30
|
+
/** DBSC (Device Bound Session Credentials) configuration. */
|
|
31
|
+
export interface DbscConfig {
|
|
32
|
+
/** Enable DBSC bound-cookie verification in the pipeline. */
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
/** Cookie name (default: '__Secure-tf-bound'). */
|
|
35
|
+
cookieName?: string;
|
|
36
|
+
/** Cookie rotation interval in seconds (default: 300). */
|
|
37
|
+
rotationInterval?: number;
|
|
38
|
+
}
|
|
25
39
|
/** Configuration for the TokenForge server middleware */
|
|
26
40
|
export interface TokenForgeServerOptions {
|
|
27
41
|
storage: TokenForgeStorageRef;
|
|
@@ -35,10 +49,23 @@ export interface TokenForgeServerOptions {
|
|
|
35
49
|
sessionMaxAge: number;
|
|
36
50
|
/** Nonce expiry in seconds (default: 60) */
|
|
37
51
|
nonceExpiry: number;
|
|
38
|
-
/** Paths that skip TokenForge verification */
|
|
52
|
+
/** Paths that skip TokenForge verification (public allowlist) */
|
|
39
53
|
skipPaths?: string[];
|
|
40
54
|
/** Paths requiring elevated trust (>90) */
|
|
41
55
|
sensitiveOps?: string[];
|
|
56
|
+
/**
|
|
57
|
+
* Behavior when a request cannot be positively verified — missing
|
|
58
|
+
* signature on a protected (non-skip) path, or an unreachable/erroring
|
|
59
|
+
* verification backend.
|
|
60
|
+
*
|
|
61
|
+
* - `'closed'` (default): default-deny. Unsigned protected requests and
|
|
62
|
+
* backend failures are REJECTED. This is the bulletproof posture.
|
|
63
|
+
* - `'open'`: legacy fail-open. Unsigned requests degrade through and
|
|
64
|
+
* backend failures pass. Use only for staged rollout behind an alarm.
|
|
65
|
+
*/
|
|
66
|
+
failMode?: 'closed' | 'open';
|
|
67
|
+
/** DBSC bound-cookie settings (disabled by default). */
|
|
68
|
+
dbsc?: DbscConfig;
|
|
42
69
|
/** Called on security events */
|
|
43
70
|
onSecurityEvent?: (event: SecurityEvent) => Promise<void>;
|
|
44
71
|
/** Email delivery callback for OTP step-up */
|
|
@@ -62,6 +89,7 @@ export interface TokenForgeStorageRef {
|
|
|
62
89
|
getSession(sessionId: string, deviceId: string): Promise<DeviceSession | null>;
|
|
63
90
|
createSession(session: DeviceSession): Promise<void>;
|
|
64
91
|
updateTrustScore(deviceId: string, trustScore: number): Promise<void>;
|
|
92
|
+
updateBoundCookieHash(deviceId: string, hash: string, expiresAt: string): Promise<void>;
|
|
65
93
|
revokeSession(deviceId: string, reason: string): Promise<void>;
|
|
66
94
|
revokeUserSessions(userId: string): Promise<void>;
|
|
67
95
|
listUserSessions(userId: string, limit: number): Promise<DeviceSession[]>;
|
|
@@ -79,6 +107,14 @@ export interface TokenForgeStorageRef {
|
|
|
79
107
|
getChallenge(challengeId: string, userId: string): Promise<unknown>;
|
|
80
108
|
updateChallengeStatus(challengeId: string, status: string, completedAt?: string): Promise<void>;
|
|
81
109
|
countRecentChallenges(userId: string, windowMinutes: number): Promise<number>;
|
|
110
|
+
getActivityHistogram(userId: string): Promise<{
|
|
111
|
+
buckets: number[];
|
|
112
|
+
totalRequests: number;
|
|
113
|
+
} | null>;
|
|
114
|
+
setActivityHistogram(userId: string, histogram: {
|
|
115
|
+
buckets: number[];
|
|
116
|
+
totalRequests: number;
|
|
117
|
+
}): Promise<void>;
|
|
82
118
|
storeOtp(challengeId: string, code: string, ttlSeconds: number): Promise<void>;
|
|
83
119
|
getOtp(challengeId: string): Promise<string | null>;
|
|
84
120
|
deleteOtp(challengeId: string): Promise<void>;
|
|
@@ -96,7 +132,7 @@ export interface SecurityEvent {
|
|
|
96
132
|
metadata: Record<string, unknown>;
|
|
97
133
|
}
|
|
98
134
|
/** All possible security event types */
|
|
99
|
-
export type SecurityEventType = 'DEVICE_BOUND' | 'SIGNATURE_INVALID' | 'IP_CHANGE' | 'GEO_ANOMALY' | 'TRUST_DROP' | 'TRUST_SCORE_CHANGE' | 'SESSION_REVOKED' | 'SESSION_EXPIRED' | 'STEP_UP_TRIGGERED' | 'STEP_UP_COMPLETED' | 'STEP_UP_FAILED' | 'NONCE_REPLAY' | 'DEVICE_MISMATCH' | 'DEVICE_NOT_FOUND' | 'TIMESTAMP_SKEW';
|
|
135
|
+
export type SecurityEventType = 'DEVICE_BOUND' | 'SIGNATURE_INVALID' | 'IP_CHANGE' | 'GEO_ANOMALY' | 'TRUST_DROP' | 'TRUST_SCORE_CHANGE' | 'SESSION_REVOKED' | 'SESSION_EXPIRED' | 'STEP_UP_TRIGGERED' | 'STEP_UP_COMPLETED' | 'STEP_UP_FAILED' | 'NONCE_REPLAY' | 'DEVICE_MISMATCH' | 'DEVICE_NOT_FOUND' | 'TIMESTAMP_SKEW' | 'DBSC_COOKIE_MISSING' | 'DBSC_COOKIE_INVALID';
|
|
100
136
|
/** Signals used by the trust score engine */
|
|
101
137
|
export interface TrustSignals {
|
|
102
138
|
signatureValid: boolean;
|
|
@@ -108,6 +144,11 @@ export interface TrustSignals {
|
|
|
108
144
|
originalFingerprint: string;
|
|
109
145
|
requestTimestamp: number;
|
|
110
146
|
sessionCreatedAt: number;
|
|
147
|
+
/** Activity histogram for time-of-day anomaly detection (optional). */
|
|
148
|
+
activityHistogram?: {
|
|
149
|
+
buckets: number[];
|
|
150
|
+
totalRequests: number;
|
|
151
|
+
};
|
|
111
152
|
}
|
|
112
153
|
/** Breakdown of trust score components */
|
|
113
154
|
export interface ScoreBreakdown {
|
|
@@ -118,6 +159,8 @@ export interface ScoreBreakdown {
|
|
|
118
159
|
velocityScore: number;
|
|
119
160
|
timeScore: number;
|
|
120
161
|
nonceScore: number;
|
|
162
|
+
/** Negative number — subtracted from total when AitM anomalies present. */
|
|
163
|
+
aitmDelta?: number;
|
|
121
164
|
total: number;
|
|
122
165
|
reasons: string[];
|
|
123
166
|
}
|
|
@@ -137,6 +180,10 @@ export interface DeviceSession {
|
|
|
137
180
|
revoked: number;
|
|
138
181
|
revoked_reason: string | null;
|
|
139
182
|
created_at: string;
|
|
183
|
+
/** SHA-256 hash of the DBSC bound cookie (if DBSC enabled). */
|
|
184
|
+
bound_cookie_hash?: string | null;
|
|
185
|
+
/** ISO timestamp when the bound cookie expires. */
|
|
186
|
+
bound_cookie_expires_at?: string | null;
|
|
140
187
|
}
|
|
141
188
|
/** Default header names */
|
|
142
189
|
export declare const TF_HEADERS: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"../src/","sources":["shared/types.ts"],"names":[],"mappings":"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"}
|
package/dist/shared/types.js
CHANGED
package/dist/shared/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"../src/","sources":["shared/types.ts"],"names":[],"mappings":"AAAA,kCAAkC;AA8BlC,OAAO,EACL,4BAA4B,EAC5B,+BAA+B,EAC/B,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AAkLvB,2BAA2B;AAC3B,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,SAAS,EAAE,gBAAgB;IAC3B,KAAK,EAAE,YAAY;IACnB,SAAS,EAAE,gBAAgB;IAC3B,SAAS,EAAE,gBAAgB;CACnB,CAAC"}
|