@exortek/apikey 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.
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @param {string} prefix
3
+ * @param {string} name
4
+ * @param {(msg: string) => Error} invalidArg
5
+ * @returns {string}
6
+ */
7
+ export function assertPrefix(prefix: string, name: string, invalidArg: (msg: string) => Error): string;
8
+ /**
9
+ * Mint the raw pieces of a new key. Returns the wire token, the
10
+ * plaintext id (for DB lookup), and the storage hash of the secret.
11
+ *
12
+ * @param {string} prefix
13
+ * @param {Buffer | null} pepper Newest pepper, or null when unconfigured.
14
+ * @returns {{ key: string, id: string, hash: string }}
15
+ */
16
+ export function mint(prefix: string, pepper: Buffer | null): {
17
+ key: string;
18
+ id: string;
19
+ hash: string;
20
+ };
21
+ /**
22
+ * Compute the storage hash of a raw secret. With a pepper: HMAC-SHA256
23
+ * keyed by the pepper. Without: plain SHA-256. Both return the digest
24
+ * as a 43-char base64url string.
25
+ *
26
+ * @param {Buffer} secretBytes
27
+ * @param {Buffer | null} pepper
28
+ * @returns {string}
29
+ */
30
+ export function hashSecret(secretBytes: Buffer, pepper: Buffer | null): string;
31
+ /**
32
+ * Timing-safe compare of a candidate hash against a stored hash. Both
33
+ * inputs are base64url strings of equal length — a length mismatch is
34
+ * treated as a mismatch after a fixed decode step, so an outside
35
+ * observer cannot learn the stored hash's length via timing.
36
+ *
37
+ * @param {string} candidate
38
+ * @param {string} stored
39
+ * @returns {boolean}
40
+ */
41
+ export function hashesMatch(candidate: string, stored: string): boolean;
42
+ /**
43
+ * Parse a raw key without verifying it. Returns the segments, or
44
+ * `null` when the shape is wrong. Never throws.
45
+ *
46
+ * Callers can use `parseApiKey(key).prefix` to route by key family
47
+ * in a middleware before hitting the store — but the parse result
48
+ * MUST NOT be trusted as authenticated. Only `verifyApiKey` proves
49
+ * the holder possesses the real secret.
50
+ *
51
+ * @param {string} key
52
+ * @returns {{ prefix: string, id: string, secret: string } | null}
53
+ */
54
+ export function parseApiKey(key: string): {
55
+ prefix: string;
56
+ id: string;
57
+ secret: string;
58
+ } | null;
59
+ /**
60
+ * Compute the storage hash for a candidate raw key's secret half,
61
+ * trying peppers newest-first. Returns the hash + which pepper matched
62
+ * (or null if no pepper array was supplied).
63
+ *
64
+ * Used by `verifyApiKey` — it hashes the incoming secret with each
65
+ * pepper in the rotation and lets the caller decide which one to
66
+ * compare against. The needsRehash signal (secret matched an older
67
+ * pepper) is exposed to consumers so they can silently upgrade
68
+ * storage on the next successful auth.
69
+ *
70
+ * @param {string} rawSecret The base64url secret segment.
71
+ * @param {Buffer[] | null} peppers
72
+ * @returns {{ candidateHashes: string[] }}
73
+ */
74
+ export function candidateHashesFor(rawSecret: string, peppers: Buffer[] | null): {
75
+ candidateHashes: string[];
76
+ };
77
+ /**
78
+ * Log-safe display for a key. Returns `<prefix>_<first-N-of-id>…<last-M-of-secret>`
79
+ * so the value is recognisable in an audit log without disclosing the
80
+ * secret. The default masks all but the first 6 chars of the id and
81
+ * the last 4 chars of the secret.
82
+ *
83
+ * @param {string} key
84
+ * @returns {string}
85
+ */
86
+ export function mask(key: string): string;
87
+ import { isBytes } from '@exortek/shared/predicates';
88
+ export { nodeTimingSafeEqual as _nodeTimingSafeEqual, isBytes as _isBytes };
package/package.json ADDED
@@ -0,0 +1,98 @@
1
+ {
2
+ "name": "@exortek/apikey",
3
+ "version": "1.0.0",
4
+ "description": "Stripe-style prefixed API keys for Node.js — 3-segment tokens (prefix_id_secret), HMAC-SHA256 storage hash with pepper rotation, scope allowlists with wildcard match, opt-in lastUsedAt tracking, memory + Redis stores, Express + Fastify middleware. Server-only. Zero non-@exortek runtime dependencies.",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.mjs",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.mjs",
14
+ "require": "./dist/index.cjs"
15
+ },
16
+ "./stores": {
17
+ "types": "./dist/stores/index.d.ts",
18
+ "import": "./dist/stores.mjs",
19
+ "require": "./dist/stores.cjs"
20
+ },
21
+ "./middleware/express": {
22
+ "types": "./dist/middleware/express.d.ts",
23
+ "import": "./dist/middleware/express.mjs",
24
+ "require": "./dist/middleware/express.cjs"
25
+ },
26
+ "./middleware/fastify": {
27
+ "types": "./dist/middleware/fastify.d.ts",
28
+ "import": "./dist/middleware/fastify.mjs",
29
+ "require": "./dist/middleware/fastify.cjs"
30
+ }
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md",
35
+ "LICENSE"
36
+ ],
37
+ "scripts": {
38
+ "build": "rm -rf dist tsconfig.tsbuildinfo && rollup -c rollup.config.js && tsc -p tsconfig.json",
39
+ "build:watch": "rollup -c rollup.config.js --watch",
40
+ "build:types": "tsc -p tsconfig.json",
41
+ "typecheck": "tsc -p tsconfig.json --noEmit",
42
+ "test": "node --test 'tests/**/*.test.js'",
43
+ "test:coverage": "node --test --experimental-test-coverage 'tests/**/*.test.js'",
44
+ "clean": "rm -rf dist tsconfig.tsbuildinfo",
45
+ "prepack": "cp ../../LICENSE ./LICENSE"
46
+ },
47
+ "keywords": [
48
+ "backend",
49
+ "security",
50
+ "auth",
51
+ "api-key",
52
+ "apikey",
53
+ "stripe",
54
+ "prefixed-token",
55
+ "hmac",
56
+ "scopes",
57
+ "server-only",
58
+ "node-crypto"
59
+ ],
60
+ "license": "MIT",
61
+ "homepage": "https://github.com/ExorTek/auth/tree/master/packages/apikey#readme",
62
+ "repository": {
63
+ "type": "git",
64
+ "url": "git+https://github.com/ExorTek/auth.git",
65
+ "directory": "packages/apikey"
66
+ },
67
+ "bugs": {
68
+ "url": "https://github.com/ExorTek/auth/issues"
69
+ },
70
+ "engines": {
71
+ "node": ">=22.0.0"
72
+ },
73
+ "peerDependencies": {
74
+ "express": ">=4",
75
+ "fastify": ">=4",
76
+ "fastify-plugin": ">=4"
77
+ },
78
+ "peerDependenciesMeta": {
79
+ "express": {
80
+ "optional": true
81
+ },
82
+ "fastify": {
83
+ "optional": true
84
+ },
85
+ "fastify-plugin": {
86
+ "optional": true
87
+ }
88
+ },
89
+ "devDependencies": {
90
+ "@exortek/shared": "0.0.0",
91
+ "express": "^5.2.1",
92
+ "fastify": "^5.10.0",
93
+ "fastify-plugin": "^6.0.0"
94
+ },
95
+ "publishConfig": {
96
+ "access": "public"
97
+ }
98
+ }