@nextage/era-lib 1.0.166 → 1.0.167
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/build/events/__mocks__/msg-wrapper.d.ts +1 -1
- package/build/events/__mocks__/nats-wrapper.d.ts +1 -1
- package/build/utils/index.d.ts +1 -0
- package/build/utils/index.d.ts.map +1 -1
- package/build/utils/index.js +1 -0
- package/build/utils/index.js.map +1 -1
- package/build/utils/jwt.d.ts +45 -0
- package/build/utils/jwt.d.ts.map +1 -0
- package/build/utils/jwt.js +106 -0
- package/build/utils/jwt.js.map +1 -0
- package/package.json +5 -2
package/build/utils/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AACtB,cAAc,iBAAiB,CAAC"}
|
package/build/utils/index.js
CHANGED
|
@@ -16,5 +16,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./express"), exports);
|
|
18
18
|
__exportStar(require("./functs"), exports);
|
|
19
|
+
__exportStar(require("./jwt"), exports);
|
|
19
20
|
__exportStar(require("./start-service"), exports);
|
|
20
21
|
//# sourceMappingURL=index.js.map
|
package/build/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,2CAAyB;AACzB,kDAAgC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,2CAAyB;AACzB,wCAAsB;AACtB,kDAAgC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { JwtPayload, SignOptions } from 'jsonwebtoken';
|
|
2
|
+
/** Marker claim distinguishing a refresh token from an access token. */
|
|
3
|
+
export declare const REFRESH_TOKEN_TYPE = "refresh";
|
|
4
|
+
/** Default validity used when the matching env var is not set. */
|
|
5
|
+
export declare const DEFAULT_ACCESS_VALIDITY = "15m";
|
|
6
|
+
export declare const DEFAULT_REFRESH_VALIDITY = "7d";
|
|
7
|
+
export interface RefreshTokenPayload extends JwtPayload {
|
|
8
|
+
/** Subject — the user id. */
|
|
9
|
+
sub: string;
|
|
10
|
+
/** JWT id — the `accesses` record id (session id). Mirrors the access token jti. */
|
|
11
|
+
jti: string;
|
|
12
|
+
/** Token type marker. */
|
|
13
|
+
typ: typeof REFRESH_TOKEN_TYPE;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Sign a long-lived REFRESH token for a session.
|
|
17
|
+
*
|
|
18
|
+
* @param sub user id
|
|
19
|
+
* @param jti `accesses` record id (session id) — same value as the access jti
|
|
20
|
+
* @param opts optional sign-option overrides (e.g. a fixed expiresIn for tests)
|
|
21
|
+
*/
|
|
22
|
+
export declare function signRefreshToken(sub: string, jti: string, opts?: SignOptions, secret?: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Verify a REFRESH token and return its payload. Throws (JsonWebTokenError /
|
|
25
|
+
* TokenExpiredError) when the token is malformed, expired or not a refresh token.
|
|
26
|
+
*/
|
|
27
|
+
export declare function verifyRefreshToken(token: string, secret?: string): RefreshTokenPayload;
|
|
28
|
+
/**
|
|
29
|
+
* Deterministic sha256 hex digest of a token. Stored on the `accesses` record so
|
|
30
|
+
* the raw refresh token never touches the database and can be rotated / revoked
|
|
31
|
+
* by overwriting (logout) or replacing (rotation) the stored hash.
|
|
32
|
+
*/
|
|
33
|
+
export declare function hashToken(token: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Read the `exp` claim of a signed token and return it as a `Date` (or
|
|
36
|
+
* `undefined` when the token carries no expiry). Used to persist the refresh
|
|
37
|
+
* token expiry on the `accesses` record without re-parsing the duration string.
|
|
38
|
+
*/
|
|
39
|
+
export declare function tokenExpiry(token: string): Date | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Constant-time comparison of a raw token against a stored hash. Prevents timing
|
|
42
|
+
* side-channels when validating a presented refresh token.
|
|
43
|
+
*/
|
|
44
|
+
export declare function verifyTokenHash(token: string, hash?: string | null): boolean;
|
|
45
|
+
//# sourceMappingURL=jwt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/utils/jwt.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEvD,wEAAwE;AACxE,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAE5C,kEAAkE;AAClE,eAAO,MAAM,uBAAuB,QAAS,CAAC;AAC9C,eAAO,MAAM,wBAAwB,OAAQ,CAAC;AAE9C,MAAM,WAAW,mBAAoB,SAAQ,UAAU;IACrD,6BAA6B;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,oFAAoF;IACpF,GAAG,EAAE,MAAM,CAAC;IACZ,yBAAyB;IACzB,GAAG,EAAE,OAAO,kBAAkB,CAAC;CAChC;AAyBD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAW1G;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAQtF;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAK3D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAS5E"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ┌────────────────────────────────────────────────────────────────────────────┐
|
|
3
|
+
// │ JWT — functional token helpers (access + refresh) │
|
|
4
|
+
// │ │
|
|
5
|
+
// │ Pure, side-effect-free helpers built on `jsonwebtoken`. They centralize the │
|
|
6
|
+
// │ token contract of the auth service so the controller stays declarative: │
|
|
7
|
+
// │ │
|
|
8
|
+
// │ • signRefreshToken() → long-lived refresh JWT (REFRESH_VALIDITY) │
|
|
9
|
+
// │ • verifyRefreshToken() → decode + verify a refresh JWT (throws on invalid) │
|
|
10
|
+
// │ • hashToken() → sha256 hex, stored on the `accesses` record so the │
|
|
11
|
+
// │ refresh can be rotated / revoked server-side. │
|
|
12
|
+
// │ │
|
|
13
|
+
// │ The ACCESS token is still signed by nx-frame-be `generateJwt()` (it already │
|
|
14
|
+
// │ honours JWT_VALIDITY). See ADR-0002: the target architecture (Step 2.7) is │
|
|
15
|
+
// │ asymmetric signing (EdDSA/Ed25519 via `jose`, auth-srv sole signer). These │
|
|
16
|
+
// │ helpers keep HS* now with a clean, functional surface to swap later. │
|
|
17
|
+
// └────────────────────────────────────────────────────────────────────────────┘
|
|
18
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
19
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.DEFAULT_REFRESH_VALIDITY = exports.DEFAULT_ACCESS_VALIDITY = exports.REFRESH_TOKEN_TYPE = void 0;
|
|
23
|
+
exports.signRefreshToken = signRefreshToken;
|
|
24
|
+
exports.verifyRefreshToken = verifyRefreshToken;
|
|
25
|
+
exports.hashToken = hashToken;
|
|
26
|
+
exports.tokenExpiry = tokenExpiry;
|
|
27
|
+
exports.verifyTokenHash = verifyTokenHash;
|
|
28
|
+
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
29
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
30
|
+
/** Marker claim distinguishing a refresh token from an access token. */
|
|
31
|
+
exports.REFRESH_TOKEN_TYPE = 'refresh';
|
|
32
|
+
/** Default validity used when the matching env var is not set. */
|
|
33
|
+
exports.DEFAULT_ACCESS_VALIDITY = '15m';
|
|
34
|
+
exports.DEFAULT_REFRESH_VALIDITY = '7d';
|
|
35
|
+
/**
|
|
36
|
+
* Resolve the secret used to sign / verify REFRESH tokens.
|
|
37
|
+
*
|
|
38
|
+
* A dedicated `REFRESH_SECRET` is preferred (so a leak of one secret cannot be
|
|
39
|
+
* used to forge the other kind of token); it falls back to `JWT_SECRET` when not
|
|
40
|
+
* configured. Throws when neither is available.
|
|
41
|
+
*/
|
|
42
|
+
function refreshSecret(secret) {
|
|
43
|
+
const resolved = secret || process.env.REFRESH_SECRET || process.env.JWT_SECRET;
|
|
44
|
+
if (!resolved)
|
|
45
|
+
throw new Error('Missing refresh token secret (REFRESH_SECRET / JWT_SECRET)');
|
|
46
|
+
return resolved;
|
|
47
|
+
}
|
|
48
|
+
/** Resolve the signing algorithm (defaults to HS512, matching the access token). */
|
|
49
|
+
function signAlgorithm() {
|
|
50
|
+
return (process.env.JWT_ALGORITHM ?? 'HS512');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Sign a long-lived REFRESH token for a session.
|
|
54
|
+
*
|
|
55
|
+
* @param sub user id
|
|
56
|
+
* @param jti `accesses` record id (session id) — same value as the access jti
|
|
57
|
+
* @param opts optional sign-option overrides (e.g. a fixed expiresIn for tests)
|
|
58
|
+
*/
|
|
59
|
+
function signRefreshToken(sub, jti, opts = {}, secret) {
|
|
60
|
+
const signOpts = {
|
|
61
|
+
algorithm: signAlgorithm(),
|
|
62
|
+
expiresIn: (process.env.REFRESH_VALIDITY ?? exports.DEFAULT_REFRESH_VALIDITY),
|
|
63
|
+
...opts
|
|
64
|
+
};
|
|
65
|
+
const payload = { sub, jti, typ: exports.REFRESH_TOKEN_TYPE };
|
|
66
|
+
return jsonwebtoken_1.default.sign(payload, refreshSecret(secret), signOpts);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Verify a REFRESH token and return its payload. Throws (JsonWebTokenError /
|
|
70
|
+
* TokenExpiredError) when the token is malformed, expired or not a refresh token.
|
|
71
|
+
*/
|
|
72
|
+
function verifyRefreshToken(token, secret) {
|
|
73
|
+
const payload = jsonwebtoken_1.default.verify(token, refreshSecret(secret), { algorithms: [signAlgorithm()] });
|
|
74
|
+
if (payload?.typ !== exports.REFRESH_TOKEN_TYPE)
|
|
75
|
+
throw new Error('Not a refresh token');
|
|
76
|
+
return payload;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Deterministic sha256 hex digest of a token. Stored on the `accesses` record so
|
|
80
|
+
* the raw refresh token never touches the database and can be rotated / revoked
|
|
81
|
+
* by overwriting (logout) or replacing (rotation) the stored hash.
|
|
82
|
+
*/
|
|
83
|
+
function hashToken(token) {
|
|
84
|
+
return node_crypto_1.default.createHash('sha256').update(token).digest('hex');
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Read the `exp` claim of a signed token and return it as a `Date` (or
|
|
88
|
+
* `undefined` when the token carries no expiry). Used to persist the refresh
|
|
89
|
+
* token expiry on the `accesses` record without re-parsing the duration string.
|
|
90
|
+
*/
|
|
91
|
+
function tokenExpiry(token) {
|
|
92
|
+
const decoded = jsonwebtoken_1.default.decode(token);
|
|
93
|
+
return decoded?.exp ? new Date(decoded.exp * 1000) : undefined;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Constant-time comparison of a raw token against a stored hash. Prevents timing
|
|
97
|
+
* side-channels when validating a presented refresh token.
|
|
98
|
+
*/
|
|
99
|
+
function verifyTokenHash(token, hash) {
|
|
100
|
+
if (!hash)
|
|
101
|
+
return false;
|
|
102
|
+
const a = Buffer.from(hashToken(token));
|
|
103
|
+
const b = Buffer.from(hash);
|
|
104
|
+
return a.length === b.length && node_crypto_1.default.timingSafeEqual(a, b);
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=jwt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../src/utils/jwt.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextage/era-lib",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.167",
|
|
4
4
|
"main": "./build/index.js",
|
|
5
5
|
"types": "./build/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -55,6 +55,9 @@
|
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"del-cli": "^6.0.0",
|
|
57
57
|
"mongodb-memory-server": "^10.1.4",
|
|
58
|
-
"vitest": "^
|
|
58
|
+
"vitest": "^4.1.10"
|
|
59
|
+
},
|
|
60
|
+
"overrides": {
|
|
61
|
+
"uuid": "^11.1.1"
|
|
59
62
|
}
|
|
60
63
|
}
|