@fluojs/passport 1.0.0-beta.1

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 (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.ko.md +179 -0
  3. package/README.md +179 -0
  4. package/dist/account/account-linking.d.ts +91 -0
  5. package/dist/account/account-linking.d.ts.map +1 -0
  6. package/dist/account/account-linking.js +145 -0
  7. package/dist/adapters/passport-js.d.ts +77 -0
  8. package/dist/adapters/passport-js.d.ts.map +1 -0
  9. package/dist/adapters/passport-js.js +230 -0
  10. package/dist/cookie/cookie-auth-module.d.ts +65 -0
  11. package/dist/cookie/cookie-auth-module.d.ts.map +1 -0
  12. package/dist/cookie/cookie-auth-module.js +84 -0
  13. package/dist/cookie/cookie-auth.d.ts +40 -0
  14. package/dist/cookie/cookie-auth.d.ts.map +1 -0
  15. package/dist/cookie/cookie-auth.js +101 -0
  16. package/dist/cookie/cookie-manager.d.ts +34 -0
  17. package/dist/cookie/cookie-manager.d.ts.map +1 -0
  18. package/dist/cookie/cookie-manager.js +93 -0
  19. package/dist/decorators.d.ts +42 -0
  20. package/dist/decorators.d.ts.map +1 -0
  21. package/dist/decorators.js +95 -0
  22. package/dist/errors.d.ts +26 -0
  23. package/dist/errors.d.ts.map +1 -0
  24. package/dist/errors.js +48 -0
  25. package/dist/guard.d.ts +39 -0
  26. package/dist/guard.d.ts.map +1 -0
  27. package/dist/guard.js +124 -0
  28. package/dist/index.d.ts +15 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +14 -0
  31. package/dist/internal-tokens.d.ts +3 -0
  32. package/dist/internal-tokens.d.ts.map +1 -0
  33. package/dist/internal-tokens.js +4 -0
  34. package/dist/metadata.d.ts +6 -0
  35. package/dist/metadata.d.ts.map +1 -0
  36. package/dist/metadata.js +105 -0
  37. package/dist/module.d.ts +36 -0
  38. package/dist/module.d.ts.map +1 -0
  39. package/dist/module.js +63 -0
  40. package/dist/refresh/jwt-refresh-token-adapter.d.ts +30 -0
  41. package/dist/refresh/jwt-refresh-token-adapter.d.ts.map +1 -0
  42. package/dist/refresh/jwt-refresh-token-adapter.js +103 -0
  43. package/dist/refresh/refresh-token.d.ts +96 -0
  44. package/dist/refresh/refresh-token.d.ts.map +1 -0
  45. package/dist/refresh/refresh-token.js +178 -0
  46. package/dist/scope.d.ts +5 -0
  47. package/dist/scope.d.ts.map +1 -0
  48. package/dist/scope.js +44 -0
  49. package/dist/status.d.ts +36 -0
  50. package/dist/status.d.ts.map +1 -0
  51. package/dist/status.js +173 -0
  52. package/dist/types.d.ts +36 -0
  53. package/dist/types.d.ts.map +1 -0
  54. package/dist/types.js +1 -0
  55. package/package.json +55 -0
@@ -0,0 +1,36 @@
1
+ import { type ModuleType } from '@fluojs/runtime';
2
+ import type { AuthStrategyRegistration, PassportModuleOptions } from './types.js';
3
+ type PassportModuleType = ModuleType;
4
+ /**
5
+ * Canonical module-first entrypoint for passport strategy wiring.
6
+ */
7
+ export declare class PassportModule {
8
+ /**
9
+ * Registers passport options, the auth strategy registry, and {@link AuthGuard}.
10
+ *
11
+ * @param options Module-level auth defaults such as `defaultStrategy`.
12
+ * @param strategies Named strategy registrations exposed to `@UseAuth(...)` and the fallback default strategy.
13
+ * @returns A module definition that exports `AuthGuard` and keeps the strategy registry internal.
14
+ * @throws {AuthStrategyResolutionError} When duplicate strategy names are registered.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { Module } from '@fluojs/core';
19
+ * import { PassportModule } from '@fluojs/passport';
20
+ *
21
+ * @Module({
22
+ * imports: [
23
+ * PassportModule.forRoot(
24
+ * { defaultStrategy: 'jwt' },
25
+ * [{ name: 'jwt', token: JwtStrategy }],
26
+ * ),
27
+ * ],
28
+ * providers: [JwtStrategy],
29
+ * })
30
+ * export class AuthModule {}
31
+ * ```
32
+ */
33
+ static forRoot(options?: PassportModuleOptions, strategies?: AuthStrategyRegistration[]): PassportModuleType;
34
+ }
35
+ export {};
36
+ //# sourceMappingURL=module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAKhE,OAAO,KAAK,EACV,wBAAwB,EAExB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAgBpB,KAAK,kBAAkB,GAAG,UAAU,CAAC;AAmBrC;;GAEG;AACH,qBAAa,cAAc;IACzB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,MAAM,CAAC,OAAO,CACZ,OAAO,GAAE,qBAA0B,EACnC,UAAU,GAAE,wBAAwB,EAAO,GAC1C,kBAAkB;CAQtB"}
package/dist/module.js ADDED
@@ -0,0 +1,63 @@
1
+ import { defineModule } from '@fluojs/runtime';
2
+ import { AuthStrategyResolutionError } from './errors.js';
3
+ import { AuthGuard } from './guard.js';
4
+ import { AUTH_STRATEGY_REGISTRY, PASSPORT_OPTIONS } from './internal-tokens.js';
5
+ function createStrategyRegistry(strategies) {
6
+ const registry = Object.create(null);
7
+ for (const strategy of strategies) {
8
+ if (Object.hasOwn(registry, strategy.name)) {
9
+ throw new AuthStrategyResolutionError(`Duplicate auth strategy registration for "${strategy.name}".`);
10
+ }
11
+ registry[strategy.name] = strategy.token;
12
+ }
13
+ return registry;
14
+ }
15
+ function createPassportModuleProviders(options = {}, strategies = []) {
16
+ return [{
17
+ provide: PASSPORT_OPTIONS,
18
+ useValue: {
19
+ ...options
20
+ }
21
+ }, {
22
+ provide: AUTH_STRATEGY_REGISTRY,
23
+ useValue: createStrategyRegistry(strategies)
24
+ }, AuthGuard];
25
+ }
26
+
27
+ /**
28
+ * Canonical module-first entrypoint for passport strategy wiring.
29
+ */
30
+ export class PassportModule {
31
+ /**
32
+ * Registers passport options, the auth strategy registry, and {@link AuthGuard}.
33
+ *
34
+ * @param options Module-level auth defaults such as `defaultStrategy`.
35
+ * @param strategies Named strategy registrations exposed to `@UseAuth(...)` and the fallback default strategy.
36
+ * @returns A module definition that exports `AuthGuard` and keeps the strategy registry internal.
37
+ * @throws {AuthStrategyResolutionError} When duplicate strategy names are registered.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * import { Module } from '@fluojs/core';
42
+ * import { PassportModule } from '@fluojs/passport';
43
+ *
44
+ * @Module({
45
+ * imports: [
46
+ * PassportModule.forRoot(
47
+ * { defaultStrategy: 'jwt' },
48
+ * [{ name: 'jwt', token: JwtStrategy }],
49
+ * ),
50
+ * ],
51
+ * providers: [JwtStrategy],
52
+ * })
53
+ * export class AuthModule {}
54
+ * ```
55
+ */
56
+ static forRoot(options = {}, strategies = []) {
57
+ class PassportRootModule extends PassportModule {}
58
+ return defineModule(PassportRootModule, {
59
+ exports: [AuthGuard],
60
+ providers: createPassportModuleProviders(options, strategies)
61
+ });
62
+ }
63
+ }
@@ -0,0 +1,30 @@
1
+ import { DefaultJwtSigner, DefaultJwtVerifier, type RefreshTokenStore } from '@fluojs/jwt';
2
+ import type { RefreshTokenService } from './refresh-token.js';
3
+ /**
4
+ * Provides refresh-token module options through dependency injection.
5
+ */
6
+ export declare const REFRESH_TOKEN_MODULE_OPTIONS: unique symbol;
7
+ /**
8
+ * Configures refresh-token storage, rotation, and secret material.
9
+ */
10
+ export interface RefreshTokenModuleOptions {
11
+ expiresInSeconds?: number;
12
+ rotation?: boolean;
13
+ secret: string;
14
+ store: RefreshTokenStore | 'memory';
15
+ }
16
+ /**
17
+ * Bridges JWT refresh-token primitives into the passport refresh-token service contract.
18
+ */
19
+ export declare class JwtRefreshTokenAdapter implements RefreshTokenService {
20
+ private readonly service;
21
+ constructor(signer: DefaultJwtSigner, verifier: DefaultJwtVerifier, options: RefreshTokenModuleOptions);
22
+ issueRefreshToken(subject: string): Promise<string>;
23
+ rotateRefreshToken(currentToken: string): Promise<{
24
+ accessToken: string;
25
+ refreshToken: string;
26
+ }>;
27
+ revokeRefreshToken(tokenId: string): Promise<void>;
28
+ revokeAllForSubject(subject: string): Promise<void>;
29
+ }
30
+ //# sourceMappingURL=jwt-refresh-token-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt-refresh-token-adapter.d.ts","sourceRoot":"","sources":["../../src/refresh/jwt-refresh-token-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAGlB,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D;;GAEG;AACH,eAAO,MAAM,4BAA4B,eAA2D,CAAC;AAErG;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,iBAAiB,GAAG,QAAQ,CAAC;CACrC;AA2ED;;GAEG;AACH,qBACa,sBAAuB,YAAW,mBAAmB;IAChE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;gBAG/C,MAAM,EAAE,gBAAgB,EACxB,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,EAAE,yBAAyB;IAuB9B,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAInD,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IAIhG,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG1D"}
@@ -0,0 +1,103 @@
1
+ let _initClass;
2
+ function _applyDecs(e, t, n, r, o, i) { var a, c, u, s, f, l, p, d = Symbol.metadata || Symbol.for("Symbol.metadata"), m = Object.defineProperty, h = Object.create, y = [h(null), h(null)], v = t.length; function g(t, n, r) { return function (o, i) { n && (i = o, o = e); for (var a = 0; a < t.length; a++) i = t[a].apply(o, r ? [i] : []); return r ? i : o; }; } function b(e, t, n, r) { if ("function" != typeof e && (r || void 0 !== e)) throw new TypeError(t + " must " + (n || "be") + " a function" + (r ? "" : " or undefined")); return e; } function applyDec(e, t, n, r, o, i, u, s, f, l, p) { function d(e) { if (!p(e)) throw new TypeError("Attempted to access private element on non-instance"); } var h = [].concat(t[0]), v = t[3], w = !u, D = 1 === o, S = 3 === o, j = 4 === o, E = 2 === o; function I(t, n, r) { return function (o, i) { return n && (i = o, o = e), r && r(o), P[t].call(o, i); }; } if (!w) { var P = {}, k = [], F = S ? "get" : j || D ? "set" : "value"; if (f ? (l || D ? P = { get: _setFunctionName(function () { return v(this); }, r, "get"), set: function (e) { t[4](this, e); } } : P[F] = v, l || _setFunctionName(P[F], r, E ? "" : F)) : l || (P = Object.getOwnPropertyDescriptor(e, r)), !l && !f) { if ((c = y[+s][r]) && 7 !== (c ^ o)) throw Error("Decorating two elements with the same name (" + P[F].name + ") is not supported yet"); y[+s][r] = o < 3 ? 1 : o; } } for (var N = e, O = h.length - 1; O >= 0; O -= n ? 2 : 1) { var T = b(h[O], "A decorator", "be", !0), z = n ? h[O - 1] : void 0, A = {}, H = { kind: ["field", "accessor", "method", "getter", "setter", "class"][o], name: r, metadata: a, addInitializer: function (e, t) { if (e.v) throw new TypeError("attempted to call addInitializer after decoration was finished"); b(t, "An initializer", "be", !0), i.push(t); }.bind(null, A) }; if (w) c = T.call(z, N, H), A.v = 1, b(c, "class decorators", "return") && (N = c);else if (H.static = s, H.private = f, c = H.access = { has: f ? p.bind() : function (e) { return r in e; } }, j || (c.get = f ? E ? function (e) { return d(e), P.value; } : I("get", 0, d) : function (e) { return e[r]; }), E || S || (c.set = f ? I("set", 0, d) : function (e, t) { e[r] = t; }), N = T.call(z, D ? { get: P.get, set: P.set } : P[F], H), A.v = 1, D) { if ("object" == typeof N && N) (c = b(N.get, "accessor.get")) && (P.get = c), (c = b(N.set, "accessor.set")) && (P.set = c), (c = b(N.init, "accessor.init")) && k.unshift(c);else if (void 0 !== N) throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined"); } else b(N, (l ? "field" : "method") + " decorators", "return") && (l ? k.unshift(N) : P[F] = N); } return o < 2 && u.push(g(k, s, 1), g(i, s, 0)), l || w || (f ? D ? u.splice(-1, 0, I("get", s), I("set", s)) : u.push(E ? P[F] : b.call.bind(P[F])) : m(e, r, P)), N; } function w(e) { return m(e, d, { configurable: !0, enumerable: !0, value: a }); } return void 0 !== i && (a = i[d]), a = h(null == a ? null : a), f = [], l = function (e) { e && f.push(g(e)); }, p = function (t, r) { for (var i = 0; i < n.length; i++) { var a = n[i], c = a[1], l = 7 & c; if ((8 & c) == t && !l == r) { var p = a[2], d = !!a[3], m = 16 & c; applyDec(t ? e : e.prototype, a, m, d ? "#" + p : _toPropertyKey(p), l, l < 2 ? [] : t ? s = s || [] : u = u || [], f, !!t, d, r, t && d ? function (t) { return _checkInRHS(t) === e; } : o); } } }, p(8, 0), p(0, 0), p(8, 1), p(0, 1), l(u), l(s), c = f, v || w(e), { e: c, get c() { var n = []; return v && [w(e = applyDec(e, [t], r, e.name, 5, n)), g(n, 1)]; } }; }
3
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
4
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
5
+ function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : ""); try { Object.defineProperty(e, "name", { configurable: !0, value: n ? n + " " + t : t }); } catch (e) {} return e; }
6
+ function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
7
+ import { Inject } from '@fluojs/core';
8
+ import { DefaultJwtSigner, DefaultJwtVerifier, JwtConfigurationError, RefreshTokenService as JwtRefreshTokenService } from '@fluojs/jwt';
9
+ /**
10
+ * Provides refresh-token module options through dependency injection.
11
+ */
12
+ export const REFRESH_TOKEN_MODULE_OPTIONS = Symbol.for('fluo.passport.refresh-token-module-options');
13
+
14
+ /**
15
+ * Configures refresh-token storage, rotation, and secret material.
16
+ */
17
+
18
+ function resolveSecret(options) {
19
+ if (!options.secret) {
20
+ throw new JwtConfigurationError('Refresh token secret is not configured. Provide it via RefreshTokenModuleOptions.secret.');
21
+ }
22
+ return options.secret;
23
+ }
24
+ function createInMemoryStore() {
25
+ const records = new Map();
26
+ return {
27
+ async save(token) {
28
+ records.set(token.id, token);
29
+ },
30
+ async find(tokenId) {
31
+ return records.get(tokenId);
32
+ },
33
+ async revoke(tokenId) {
34
+ records.delete(tokenId);
35
+ },
36
+ async revokeBySubject(subject) {
37
+ for (const [id, record] of records.entries()) {
38
+ if (record.subject === subject) {
39
+ records.delete(id);
40
+ }
41
+ }
42
+ },
43
+ async consume(input) {
44
+ const record = records.get(input.tokenId);
45
+ if (!record) {
46
+ return 'invalid';
47
+ }
48
+ if (record.subject !== input.subject || record.family !== input.family) {
49
+ return 'invalid';
50
+ }
51
+ if (record.expiresAt.getTime() <= input.now.getTime()) {
52
+ return 'expired';
53
+ }
54
+ if (record.used) {
55
+ return 'already_used';
56
+ }
57
+ records.set(input.tokenId, {
58
+ ...record,
59
+ used: true
60
+ });
61
+ return 'consumed';
62
+ }
63
+ };
64
+ }
65
+
66
+ /**
67
+ * Bridges JWT refresh-token primitives into the passport refresh-token service contract.
68
+ */
69
+ let _JwtRefreshTokenAdapt;
70
+ class JwtRefreshTokenAdapter {
71
+ static {
72
+ [_JwtRefreshTokenAdapt, _initClass] = _applyDecs(this, [Inject(DefaultJwtSigner, DefaultJwtVerifier, REFRESH_TOKEN_MODULE_OPTIONS)], []).c;
73
+ }
74
+ service;
75
+ constructor(signer, verifier, options) {
76
+ if (!options.store) {
77
+ throw new JwtConfigurationError('JwtRefreshTokenAdapter requires a persistent RefreshTokenStore. ' + 'Provide one via RefreshTokenModuleOptions.store, or pass store: \'memory\' to explicitly opt into the in-memory store (single-instance / development only).');
78
+ }
79
+ const store = options.store === 'memory' ? createInMemoryStore() : options.store;
80
+ this.service = new JwtRefreshTokenService({
81
+ expiresInSeconds: options.expiresInSeconds ?? 604800,
82
+ rotation: options.rotation ?? true,
83
+ secret: resolveSecret(options),
84
+ store
85
+ }, signer, verifier);
86
+ }
87
+ async issueRefreshToken(subject) {
88
+ return this.service.issueRefreshToken(subject);
89
+ }
90
+ async rotateRefreshToken(currentToken) {
91
+ return this.service.rotateRefreshToken(currentToken);
92
+ }
93
+ async revokeRefreshToken(tokenId) {
94
+ return this.service.revokeRefreshToken(tokenId);
95
+ }
96
+ async revokeAllForSubject(subject) {
97
+ return this.service.revokeAllForSubject(subject);
98
+ }
99
+ static {
100
+ _initClass();
101
+ }
102
+ }
103
+ export { _JwtRefreshTokenAdapt as JwtRefreshTokenAdapter };
@@ -0,0 +1,96 @@
1
+ import type { GuardContext } from '@fluojs/http';
2
+ import { type Token } from '@fluojs/core';
3
+ import { DefaultJwtVerifier } from '@fluojs/jwt';
4
+ import { type ModuleType } from '@fluojs/runtime';
5
+ import type { AuthStrategy, AuthStrategyRegistration, AuthStrategyResult } from '../types.js';
6
+ /**
7
+ * Defines the operations required to issue, rotate, and revoke refresh tokens.
8
+ */
9
+ export interface RefreshTokenService {
10
+ issueRefreshToken(subject: string): Promise<string>;
11
+ rotateRefreshToken(currentToken: string): Promise<{
12
+ accessToken: string;
13
+ refreshToken: string;
14
+ }>;
15
+ revokeRefreshToken(tokenId: string): Promise<void>;
16
+ revokeAllForSubject(subject: string): Promise<void>;
17
+ }
18
+ /**
19
+ * Identifies the active refresh-token service implementation in dependency injection.
20
+ */
21
+ export declare const REFRESH_TOKEN_SERVICE: unique symbol;
22
+ /**
23
+ * Represents the refresh-token payload accepted by refresh endpoints.
24
+ */
25
+ export interface RefreshTokenInput {
26
+ refreshToken: string;
27
+ }
28
+ /**
29
+ * Captures the token pair returned after a successful refresh-token exchange.
30
+ */
31
+ export interface RefreshTokenAuthResult {
32
+ accessToken: string;
33
+ refreshToken: string;
34
+ subject: string;
35
+ }
36
+ /**
37
+ * Identifies the built-in refresh-token authentication strategy.
38
+ */
39
+ export declare const REFRESH_TOKEN_STRATEGY_NAME = "refresh-token";
40
+ type RefreshTokenModuleType = ModuleType;
41
+ /**
42
+ * Authenticates refresh-token requests and exchanges them for a fresh token pair.
43
+ */
44
+ export declare class RefreshTokenStrategy implements AuthStrategy {
45
+ private readonly refreshTokenService;
46
+ private readonly verifier;
47
+ constructor(refreshTokenService: RefreshTokenService, verifier: DefaultJwtVerifier);
48
+ authenticate(context: GuardContext): Promise<AuthStrategyResult>;
49
+ private rotateRefreshToken;
50
+ private extractRefreshToken;
51
+ private normalizeRefreshToken;
52
+ private extractVerifiedSubject;
53
+ }
54
+ /**
55
+ * Creates the passport strategy registration for the built-in refresh-token strategy.
56
+ *
57
+ * @returns The named strategy registration consumed by `PassportModule.forRoot(...)`.
58
+ */
59
+ export declare function createRefreshTokenStrategyRegistration(): AuthStrategyRegistration;
60
+ /**
61
+ * Canonical module-first entrypoint for refresh-token strategy support.
62
+ */
63
+ export declare class RefreshTokenModule {
64
+ /**
65
+ * Registers the shared refresh-token service alias together with `RefreshTokenStrategy`.
66
+ *
67
+ * @param service DI token for the concrete refresh-token service implementation.
68
+ * @returns A module definition that exports `RefreshTokenStrategy` and `REFRESH_TOKEN_SERVICE`.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * import { Module } from '@fluojs/core';
73
+ * import {
74
+ * PassportModule,
75
+ * RefreshTokenModule,
76
+ * RefreshTokenStrategy,
77
+ * REFRESH_TOKEN_STRATEGY_NAME,
78
+ * } from '@fluojs/passport';
79
+ *
80
+ * @Module({
81
+ * imports: [
82
+ * RefreshTokenModule.forRoot(MyRefreshTokenService),
83
+ * PassportModule.forRoot(
84
+ * { defaultStrategy: REFRESH_TOKEN_STRATEGY_NAME },
85
+ * [{ name: REFRESH_TOKEN_STRATEGY_NAME, token: RefreshTokenStrategy }],
86
+ * ),
87
+ * ],
88
+ * providers: [MyRefreshTokenService],
89
+ * })
90
+ * export class AuthModule {}
91
+ * ```
92
+ */
93
+ static forRoot(service: Token<RefreshTokenService>): RefreshTokenModuleType;
94
+ }
95
+ export {};
96
+ //# sourceMappingURL=refresh-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh-token.d.ts","sourceRoot":"","sources":["../../src/refresh/refresh-token.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAkB,MAAM,cAAc,CAAC;AACjE,OAAO,EAA0B,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AAElE,OAAO,EAAE,kBAAkB,EAA8C,MAAM,aAAa,CAAC;AAC7F,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAOhE,OAAO,KAAK,EAAE,YAAY,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAE9F;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjG,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,eAAoD,CAAC;AAEvF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,eAAO,MAAM,2BAA2B,kBAAkB,CAAC;AAI3D,KAAK,sBAAsB,GAAG,UAAU,CAAC;AAEzC;;GAEG;AACH,qBACa,oBAAqB,YAAW,YAAY;IAErD,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBADR,mBAAmB,EAAE,mBAAmB,EACxC,QAAQ,EAAE,kBAAkB;IAGzC,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,kBAAkB,CAAC;YAwBxD,kBAAkB;IAmBhC,OAAO,CAAC,mBAAmB;IAe3B,OAAO,CAAC,qBAAqB;YAYf,sBAAsB;CAQrC;AAaD;;;;GAIG;AACH,wBAAgB,sCAAsC,IAAI,wBAAwB,CAKjF;AAED;;GAEG;AACH,qBAAa,kBAAkB;IAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,mBAAmB,CAAC,GAAG,sBAAsB;CAQ5E"}
@@ -0,0 +1,178 @@
1
+ let _initClass;
2
+ function _applyDecs(e, t, n, r, o, i) { var a, c, u, s, f, l, p, d = Symbol.metadata || Symbol.for("Symbol.metadata"), m = Object.defineProperty, h = Object.create, y = [h(null), h(null)], v = t.length; function g(t, n, r) { return function (o, i) { n && (i = o, o = e); for (var a = 0; a < t.length; a++) i = t[a].apply(o, r ? [i] : []); return r ? i : o; }; } function b(e, t, n, r) { if ("function" != typeof e && (r || void 0 !== e)) throw new TypeError(t + " must " + (n || "be") + " a function" + (r ? "" : " or undefined")); return e; } function applyDec(e, t, n, r, o, i, u, s, f, l, p) { function d(e) { if (!p(e)) throw new TypeError("Attempted to access private element on non-instance"); } var h = [].concat(t[0]), v = t[3], w = !u, D = 1 === o, S = 3 === o, j = 4 === o, E = 2 === o; function I(t, n, r) { return function (o, i) { return n && (i = o, o = e), r && r(o), P[t].call(o, i); }; } if (!w) { var P = {}, k = [], F = S ? "get" : j || D ? "set" : "value"; if (f ? (l || D ? P = { get: _setFunctionName(function () { return v(this); }, r, "get"), set: function (e) { t[4](this, e); } } : P[F] = v, l || _setFunctionName(P[F], r, E ? "" : F)) : l || (P = Object.getOwnPropertyDescriptor(e, r)), !l && !f) { if ((c = y[+s][r]) && 7 !== (c ^ o)) throw Error("Decorating two elements with the same name (" + P[F].name + ") is not supported yet"); y[+s][r] = o < 3 ? 1 : o; } } for (var N = e, O = h.length - 1; O >= 0; O -= n ? 2 : 1) { var T = b(h[O], "A decorator", "be", !0), z = n ? h[O - 1] : void 0, A = {}, H = { kind: ["field", "accessor", "method", "getter", "setter", "class"][o], name: r, metadata: a, addInitializer: function (e, t) { if (e.v) throw new TypeError("attempted to call addInitializer after decoration was finished"); b(t, "An initializer", "be", !0), i.push(t); }.bind(null, A) }; if (w) c = T.call(z, N, H), A.v = 1, b(c, "class decorators", "return") && (N = c);else if (H.static = s, H.private = f, c = H.access = { has: f ? p.bind() : function (e) { return r in e; } }, j || (c.get = f ? E ? function (e) { return d(e), P.value; } : I("get", 0, d) : function (e) { return e[r]; }), E || S || (c.set = f ? I("set", 0, d) : function (e, t) { e[r] = t; }), N = T.call(z, D ? { get: P.get, set: P.set } : P[F], H), A.v = 1, D) { if ("object" == typeof N && N) (c = b(N.get, "accessor.get")) && (P.get = c), (c = b(N.set, "accessor.set")) && (P.set = c), (c = b(N.init, "accessor.init")) && k.unshift(c);else if (void 0 !== N) throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined"); } else b(N, (l ? "field" : "method") + " decorators", "return") && (l ? k.unshift(N) : P[F] = N); } return o < 2 && u.push(g(k, s, 1), g(i, s, 0)), l || w || (f ? D ? u.splice(-1, 0, I("get", s), I("set", s)) : u.push(E ? P[F] : b.call.bind(P[F])) : m(e, r, P)), N; } function w(e) { return m(e, d, { configurable: !0, enumerable: !0, value: a }); } return void 0 !== i && (a = i[d]), a = h(null == a ? null : a), f = [], l = function (e) { e && f.push(g(e)); }, p = function (t, r) { for (var i = 0; i < n.length; i++) { var a = n[i], c = a[1], l = 7 & c; if ((8 & c) == t && !l == r) { var p = a[2], d = !!a[3], m = 16 & c; applyDec(t ? e : e.prototype, a, m, d ? "#" + p : _toPropertyKey(p), l, l < 2 ? [] : t ? s = s || [] : u = u || [], f, !!t, d, r, t && d ? function (t) { return _checkInRHS(t) === e; } : o); } } }, p(8, 0), p(0, 0), p(8, 1), p(0, 1), l(u), l(s), c = f, v || w(e), { e: c, get c() { var n = []; return v && [w(e = applyDec(e, [t], r, e.name, 5, n)), g(n, 1)]; } }; }
3
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
4
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
5
+ function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : ""); try { Object.defineProperty(e, "name", { configurable: !0, value: n ? n + " " + t : t }); } catch (e) {} return e; }
6
+ function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
7
+ import { Inject, InvariantError } from '@fluojs/core';
8
+ import { DefaultJwtVerifier, JwtExpiredTokenError, JwtInvalidTokenError } from '@fluojs/jwt';
9
+ import { defineModule } from '@fluojs/runtime';
10
+ import { AuthenticationExpiredError, AuthenticationFailedError, AuthenticationRequiredError } from '../errors.js';
11
+
12
+ /**
13
+ * Defines the operations required to issue, rotate, and revoke refresh tokens.
14
+ */
15
+
16
+ /**
17
+ * Identifies the active refresh-token service implementation in dependency injection.
18
+ */
19
+ export const REFRESH_TOKEN_SERVICE = Symbol.for('fluo.passport.refresh-token-service');
20
+
21
+ /**
22
+ * Represents the refresh-token payload accepted by refresh endpoints.
23
+ */
24
+
25
+ /**
26
+ * Captures the token pair returned after a successful refresh-token exchange.
27
+ */
28
+
29
+ /**
30
+ * Identifies the built-in refresh-token authentication strategy.
31
+ */
32
+ export const REFRESH_TOKEN_STRATEGY_NAME = 'refresh-token';
33
+ const MALFORMED_REFRESH_TOKEN = Symbol('MALFORMED_REFRESH_TOKEN');
34
+ let _RefreshTokenStrategy;
35
+ /**
36
+ * Authenticates refresh-token requests and exchanges them for a fresh token pair.
37
+ */
38
+ class RefreshTokenStrategy {
39
+ static {
40
+ [_RefreshTokenStrategy, _initClass] = _applyDecs(this, [Inject(REFRESH_TOKEN_SERVICE, DefaultJwtVerifier)], []).c;
41
+ }
42
+ constructor(refreshTokenService, verifier) {
43
+ this.refreshTokenService = refreshTokenService;
44
+ this.verifier = verifier;
45
+ }
46
+ async authenticate(context) {
47
+ const request = context.requestContext.request;
48
+ const refreshToken = this.extractRefreshToken(request);
49
+ if (refreshToken === MALFORMED_REFRESH_TOKEN) {
50
+ throw new AuthenticationFailedError('Refresh token is malformed.');
51
+ }
52
+ if (!refreshToken) {
53
+ throw new AuthenticationRequiredError('Refresh token is required.');
54
+ }
55
+ const result = await this.rotateRefreshToken(refreshToken);
56
+ const subject = await this.extractVerifiedSubject(result.accessToken);
57
+ return {
58
+ claims: {
59
+ accessToken: result.accessToken,
60
+ refreshToken: result.refreshToken
61
+ },
62
+ subject
63
+ };
64
+ }
65
+ async rotateRefreshToken(currentToken) {
66
+ try {
67
+ return await this.refreshTokenService.rotateRefreshToken(currentToken);
68
+ } catch (error) {
69
+ if (error instanceof AuthenticationRequiredError || error instanceof AuthenticationExpiredError || error instanceof AuthenticationFailedError) {
70
+ throw error;
71
+ }
72
+ if (error instanceof JwtExpiredTokenError) {
73
+ throw new AuthenticationExpiredError('Refresh token has expired.', {
74
+ cause: error
75
+ });
76
+ }
77
+ if (error instanceof JwtInvalidTokenError) {
78
+ throw new AuthenticationFailedError('Refresh token is invalid or has been reused.', {
79
+ cause: error
80
+ });
81
+ }
82
+ throw error;
83
+ }
84
+ }
85
+ extractRefreshToken(request) {
86
+ if (request.body && typeof request.body === 'object' && 'refreshToken' in request.body) {
87
+ return this.normalizeRefreshToken(request.body.refreshToken);
88
+ }
89
+ const authHeaderRaw = request.headers?.authorization;
90
+ const authHeader = Array.isArray(authHeaderRaw) ? authHeaderRaw[0] : authHeaderRaw;
91
+ if (authHeader?.toLowerCase().startsWith('bearer ')) {
92
+ return this.normalizeRefreshToken(authHeader.slice(7));
93
+ }
94
+ const customHeader = request.headers?.['x-refresh-token'];
95
+ return this.normalizeRefreshToken(Array.isArray(customHeader) ? customHeader[0] : customHeader);
96
+ }
97
+ normalizeRefreshToken(token) {
98
+ if (token === undefined || token === null) {
99
+ return undefined;
100
+ }
101
+ if (typeof token !== 'string') {
102
+ return MALFORMED_REFRESH_TOKEN;
103
+ }
104
+ return token.length > 0 ? token : undefined;
105
+ }
106
+ async extractVerifiedSubject(accessToken) {
107
+ const principal = await this.verifier.verifyAccessToken(accessToken);
108
+ const sub = principal.claims.sub;
109
+ if (typeof sub !== 'string' || sub.length === 0) {
110
+ throw new InvariantError('Refresh token service returned an access token without a valid subject claim.');
111
+ }
112
+ return sub;
113
+ }
114
+ static {
115
+ _initClass();
116
+ }
117
+ }
118
+ export { _RefreshTokenStrategy as RefreshTokenStrategy };
119
+ function createRefreshTokenAliasProviders(service) {
120
+ return [{
121
+ provide: REFRESH_TOKEN_SERVICE,
122
+ useExisting: service
123
+ }];
124
+ }
125
+
126
+ /**
127
+ * Creates the passport strategy registration for the built-in refresh-token strategy.
128
+ *
129
+ * @returns The named strategy registration consumed by `PassportModule.forRoot(...)`.
130
+ */
131
+ export function createRefreshTokenStrategyRegistration() {
132
+ return {
133
+ name: REFRESH_TOKEN_STRATEGY_NAME,
134
+ token: _RefreshTokenStrategy
135
+ };
136
+ }
137
+
138
+ /**
139
+ * Canonical module-first entrypoint for refresh-token strategy support.
140
+ */
141
+ export class RefreshTokenModule {
142
+ /**
143
+ * Registers the shared refresh-token service alias together with `RefreshTokenStrategy`.
144
+ *
145
+ * @param service DI token for the concrete refresh-token service implementation.
146
+ * @returns A module definition that exports `RefreshTokenStrategy` and `REFRESH_TOKEN_SERVICE`.
147
+ *
148
+ * @example
149
+ * ```ts
150
+ * import { Module } from '@fluojs/core';
151
+ * import {
152
+ * PassportModule,
153
+ * RefreshTokenModule,
154
+ * RefreshTokenStrategy,
155
+ * REFRESH_TOKEN_STRATEGY_NAME,
156
+ * } from '@fluojs/passport';
157
+ *
158
+ * @Module({
159
+ * imports: [
160
+ * RefreshTokenModule.forRoot(MyRefreshTokenService),
161
+ * PassportModule.forRoot(
162
+ * { defaultStrategy: REFRESH_TOKEN_STRATEGY_NAME },
163
+ * [{ name: REFRESH_TOKEN_STRATEGY_NAME, token: RefreshTokenStrategy }],
164
+ * ),
165
+ * ],
166
+ * providers: [MyRefreshTokenService],
167
+ * })
168
+ * export class AuthModule {}
169
+ * ```
170
+ */
171
+ static forRoot(service) {
172
+ class RefreshTokenRuntimeModule extends RefreshTokenModule {}
173
+ return defineModule(RefreshTokenRuntimeModule, {
174
+ exports: [_RefreshTokenStrategy, REFRESH_TOKEN_SERVICE],
175
+ providers: [_RefreshTokenStrategy, ...createRefreshTokenAliasProviders(service)]
176
+ });
177
+ }
178
+ }
@@ -0,0 +1,5 @@
1
+ import type { AuthRequirement } from './types.js';
2
+ export declare function normalizeDeclaredScopes(scopes: unknown): string[] | undefined;
3
+ export declare function normalizePrincipalScopes(claims: Record<string, unknown>): string[] | undefined;
4
+ export declare function mergeAuthRequirements(base: AuthRequirement | undefined, extra: AuthRequirement | undefined): AuthRequirement | undefined;
5
+ //# sourceMappingURL=scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAoBlD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CAO7E;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,SAAS,CAW9F;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,eAAe,GAAG,SAAS,EACjC,KAAK,EAAE,eAAe,GAAG,SAAS,GACjC,eAAe,GAAG,SAAS,CAgB7B"}
package/dist/scope.js ADDED
@@ -0,0 +1,44 @@
1
+ function normalizeScopeItems(items) {
2
+ const seen = new Set();
3
+ const normalized = [];
4
+ for (const item of items) {
5
+ const scope = item.trim();
6
+ if (scope.length === 0 || seen.has(scope)) {
7
+ continue;
8
+ }
9
+ seen.add(scope);
10
+ normalized.push(scope);
11
+ }
12
+ return normalized.length > 0 ? normalized : undefined;
13
+ }
14
+ export function normalizeDeclaredScopes(scopes) {
15
+ if (!Array.isArray(scopes)) {
16
+ return undefined;
17
+ }
18
+ const scopeItems = scopes.filter(scope => typeof scope === 'string');
19
+ return normalizeScopeItems(scopeItems);
20
+ }
21
+ export function normalizePrincipalScopes(claims) {
22
+ if (Array.isArray(claims.scopes)) {
23
+ const scopes = claims.scopes.filter(scope => typeof scope === 'string');
24
+ return normalizeScopeItems(scopes);
25
+ }
26
+ if (typeof claims.scope === 'string') {
27
+ return normalizeScopeItems(claims.scope.split(/\s+/));
28
+ }
29
+ return undefined;
30
+ }
31
+ export function mergeAuthRequirements(base, extra) {
32
+ if (!base && !extra) {
33
+ return undefined;
34
+ }
35
+ const scopes = normalizeDeclaredScopes([...(base?.scopes ?? []), ...(extra?.scopes ?? [])]);
36
+ const strategy = extra?.strategy ?? base?.strategy;
37
+ if (!strategy && !scopes) {
38
+ return undefined;
39
+ }
40
+ return {
41
+ scopes,
42
+ strategy
43
+ };
44
+ }
@@ -0,0 +1,36 @@
1
+ import type { PlatformDiagnosticIssue, PlatformHealthReport, PlatformReadinessReport, PlatformSnapshot } from '@fluojs/runtime';
2
+ /** Snapshot payload describing passport readiness, health, ownership, and diagnostic details. */
3
+ export interface PassportPlatformStatusSnapshot {
4
+ readiness: PlatformReadinessReport;
5
+ health: PlatformHealthReport;
6
+ ownership: PlatformSnapshot['ownership'];
7
+ details: Record<string, unknown>;
8
+ }
9
+ /** Input contract for deriving passport platform health and readiness diagnostics. */
10
+ export interface PassportStatusAdapterInput {
11
+ componentId?: string;
12
+ readinessCritical?: boolean;
13
+ registeredStrategies: string[];
14
+ defaultStrategy?: string;
15
+ cookiePresetEnabled?: boolean;
16
+ cookiePresetReady?: boolean;
17
+ refreshTokenEnabled?: boolean;
18
+ refreshTokenStoreReady?: boolean;
19
+ refreshTokenStoreReason?: string;
20
+ refreshTokenDependencyId?: string;
21
+ }
22
+ /**
23
+ * Creates a platform snapshot for passport strategy wiring and preset readiness.
24
+ *
25
+ * @param input Passport readiness inputs such as registered strategies, default strategy, and preset readiness flags.
26
+ * @returns A platform snapshot containing passport health, readiness, ownership, and structured details.
27
+ */
28
+ export declare function createPassportPlatformStatusSnapshot(input: PassportStatusAdapterInput): PassportPlatformStatusSnapshot;
29
+ /**
30
+ * Creates platform diagnostic issues for passport registry and preset readiness problems.
31
+ *
32
+ * @param input Passport readiness inputs such as registered strategies, default strategy, and preset readiness flags.
33
+ * @returns Diagnostic issues describing empty registries, strategy mismatches, and preset dependency failures.
34
+ */
35
+ export declare function createPassportPlatformDiagnosticIssues(input: PassportStatusAdapterInput): PlatformDiagnosticIssue[];
36
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,oBAAoB,EACpB,uBAAuB,EACvB,gBAAgB,EACjB,MAAM,iBAAiB,CAAC;AAEzB,iGAAiG;AACjG,MAAM,WAAW,8BAA8B;IAC7C,SAAS,EAAE,uBAAuB,CAAC;IACnC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,SAAS,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACzC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,sFAAsF;AACtF,MAAM,WAAW,0BAA0B;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AAqFD;;;;;GAKG;AACH,wBAAgB,oCAAoC,CAAC,KAAK,EAAE,0BAA0B,GAAG,8BAA8B,CAsDtH;AAED;;;;;GAKG;AACH,wBAAgB,sCAAsC,CAAC,KAAK,EAAE,0BAA0B,GAAG,uBAAuB,EAAE,CAiDnH"}