@marxbiotech/signet-integration 0.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.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/dist/bearer-challenge.d.ts +27 -0
  4. package/dist/bearer-challenge.filter.d.ts +13 -0
  5. package/dist/bearer-challenge.filter.js +76 -0
  6. package/dist/bearer-challenge.filter.js.map +1 -0
  7. package/dist/bearer-challenge.js +120 -0
  8. package/dist/bearer-challenge.js.map +1 -0
  9. package/dist/config.d.ts +23 -0
  10. package/dist/config.js +56 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/deployment-profile.d.ts +25 -0
  13. package/dist/deployment-profile.js +103 -0
  14. package/dist/deployment-profile.js.map +1 -0
  15. package/dist/guard.d.ts +18 -0
  16. package/dist/guard.js +210 -0
  17. package/dist/guard.js.map +1 -0
  18. package/dist/index.d.ts +15 -0
  19. package/dist/index.js +50 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/jwt-verifier.d.ts +36 -0
  22. package/dist/jwt-verifier.js +167 -0
  23. package/dist/jwt-verifier.js.map +1 -0
  24. package/dist/log-sanitise.d.ts +3 -0
  25. package/dist/log-sanitise.js +23 -0
  26. package/dist/log-sanitise.js.map +1 -0
  27. package/dist/module.d.ts +12 -0
  28. package/dist/module.js +61 -0
  29. package/dist/module.js.map +1 -0
  30. package/dist/options.d.ts +31 -0
  31. package/dist/options.js +9 -0
  32. package/dist/options.js.map +1 -0
  33. package/dist/principal-resolver.d.ts +19 -0
  34. package/dist/principal-resolver.js +25 -0
  35. package/dist/principal-resolver.js.map +1 -0
  36. package/dist/principal.decorator.d.ts +2 -0
  37. package/dist/principal.decorator.js +28 -0
  38. package/dist/principal.decorator.js.map +1 -0
  39. package/dist/protected-resource.controller.d.ts +11 -0
  40. package/dist/protected-resource.controller.js +130 -0
  41. package/dist/protected-resource.controller.js.map +1 -0
  42. package/dist/public.decorator.d.ts +2 -0
  43. package/dist/public.decorator.js +11 -0
  44. package/dist/public.decorator.js.map +1 -0
  45. package/dist/scope-vocabulary.d.ts +17 -0
  46. package/dist/scope-vocabulary.js +52 -0
  47. package/dist/scope-vocabulary.js.map +1 -0
  48. package/dist/strategy.d.ts +16 -0
  49. package/dist/strategy.js +89 -0
  50. package/dist/strategy.js.map +1 -0
  51. package/dist/testing/fixture.d.ts +8 -0
  52. package/dist/testing/fixture.js +38 -0
  53. package/dist/testing/fixture.js.map +1 -0
  54. package/dist/testing/index.d.ts +3 -0
  55. package/dist/testing/index.js +11 -0
  56. package/dist/testing/index.js.map +1 -0
  57. package/dist/testing/jwks-server.d.ts +10 -0
  58. package/dist/testing/jwks-server.js +33 -0
  59. package/dist/testing/jwks-server.js.map +1 -0
  60. package/dist/testing/signet-token.d.ts +18 -0
  61. package/dist/testing/signet-token.js +31 -0
  62. package/dist/testing/signet-token.js.map +1 -0
  63. package/dist/validate-options.d.ts +8 -0
  64. package/dist/validate-options.js +88 -0
  65. package/dist/validate-options.js.map +1 -0
  66. package/package.json +93 -0
package/dist/guard.js ADDED
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.SignetBearerGuard = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const core_1 = require("@nestjs/core");
18
+ const passport_1 = require("@nestjs/passport");
19
+ const bearer_challenge_1 = require("./bearer-challenge");
20
+ const deployment_profile_1 = require("./deployment-profile");
21
+ const log_sanitise_1 = require("./log-sanitise");
22
+ const options_1 = require("./options");
23
+ const principal_resolver_1 = require("./principal-resolver");
24
+ const public_decorator_1 = require("./public.decorator");
25
+ const strategy_1 = require("./strategy");
26
+ // The decision line's own keys. A resolver's `logFields` may not reuse them:
27
+ // a second `metric=` or `clientId=` on one line is whichever copy the log
28
+ // parser keeps, and operators alert on these.
29
+ const RESERVED_LOG_KEYS = new Set([
30
+ 'metric',
31
+ 'reason',
32
+ 'clientId',
33
+ 'environment',
34
+ ]);
35
+ // Nest's OPTIONAL_DEPS_METADATA. `@nestjs/common` does not re-export it.
36
+ const OPTIONAL_PARAMTYPES = 'optional:paramtypes';
37
+ // AuthGuard's mixin marks its constructor parameter 0 `@Optional()`.
38
+ // `Reflect.getMetadata` walks the constructor prototype chain, so a subclass
39
+ // that never writes its own list treats ITS parameter 0 — the principal
40
+ // resolver — as optional. `@Optional()` on a later parameter copies that
41
+ // inherited list onto this constructor before appending its own index.
42
+ // Parameter decorators run before this one, so the copy is already own
43
+ // metadata by the time this drops index 0 (and writes a list when absent).
44
+ function requirePrincipalResolver() {
45
+ return (target) => {
46
+ const own = Reflect.getOwnMetadata(OPTIONAL_PARAMTYPES, target);
47
+ const optionalIndexes = Array.isArray(own)
48
+ ? own.filter((index) => index !== 0)
49
+ : [];
50
+ Reflect.defineMetadata(OPTIONAL_PARAMTYPES, optionalIndexes, target);
51
+ };
52
+ }
53
+ // The Bearer channel's guard: Passport dispatches SignetJwtStrategy, and a
54
+ // false from it is a uniform 401. A route marked `@Public()` (on the handler
55
+ // or its class) is let through first, so the guard can be an APP_GUARD on
56
+ // its own; a consumer with a credential dispatcher of its own decides
57
+ // `@Public()` there and never hands a public route to this guard. What
58
+ // follows is the layer on top:
59
+ //
60
+ // token lacks the admission scope → 403 (service scope), with an
61
+ // insufficient_scope challenge
62
+ // resolver says { ok: false } → 403, bare
63
+ // resolver throws PrincipalStoreUnavailableError → 503, fail closed
64
+ // resolver throws an HttpException → its own status
65
+ // resolver throws anything else → 500, the error under its own name
66
+ // Passport passed but attached no user → 500, programming error
67
+ //
68
+ // None of these are 401: the token was valid. The 403 messages distinguish
69
+ // "get a token with the right scope" from "ask an administrator" without
70
+ // naming what the caller does not hold. The 500 is deliberately NOT a 503:
71
+ // a bug in the resolver must not send the operator to check the database.
72
+ let SignetBearerGuard = class SignetBearerGuard extends (0, passport_1.AuthGuard)(strategy_1.SIGNET_JWT_STRATEGY) {
73
+ resolver;
74
+ profiles;
75
+ signetOptions;
76
+ reflector;
77
+ // The subclass's name when a consumer subclasses this guard, so its log
78
+ // `context` keeps the name the consumer's operators filter on.
79
+ logger = new common_1.Logger(this.constructor.name);
80
+ constructor(resolver, profiles, signetOptions, reflector) {
81
+ super();
82
+ this.resolver = resolver;
83
+ this.profiles = profiles;
84
+ this.signetOptions = signetOptions;
85
+ this.reflector = reflector;
86
+ }
87
+ async canActivate(context) {
88
+ if (this.reflector.getAllAndOverride(public_decorator_1.IS_PUBLIC_ROUTE, [
89
+ context.getHandler(),
90
+ context.getClass(),
91
+ ]) === true) {
92
+ return true;
93
+ }
94
+ // Typed unknown: the base declares boolean | Promise<boolean> |
95
+ // Observable<boolean>, and anything other than a literal true is treated
96
+ // as "did not pass".
97
+ let passed;
98
+ try {
99
+ passed = await super.canActivate(context);
100
+ }
101
+ catch (error) {
102
+ // Passport's own UnauthorizedException carries a message; the contract
103
+ // is one indistinguishable 401. Anything else is a programming error
104
+ // and must not be dressed up as an authentication failure.
105
+ if (error instanceof common_1.UnauthorizedException) {
106
+ throw new common_1.UnauthorizedException();
107
+ }
108
+ throw error;
109
+ }
110
+ const request = context.switchToHttp().getRequest();
111
+ const identity = request.user;
112
+ if (passed !== true || identity === undefined) {
113
+ this.logFailure('signet strategy did not pass cleanly', 'signet_identity_missing', 'none');
114
+ throw new common_1.InternalServerErrorException('signet strategy did not pass cleanly');
115
+ }
116
+ const { admissionScope } = this.signetOptions;
117
+ if (!identity.scopes.includes(admissionScope)) {
118
+ this.logger.warn(`signet token lacks service scope: metric=signet_scope_missing source=${(0, log_sanitise_1.sanitiseLogToken)(request.ip ?? 'none')}`);
119
+ // A 403 a client CAN fix by re-authorising (RFC 6750 §3.1); the
120
+ // resolver's refusals below stay bare, because a wider OAuth scope
121
+ // would not supply a missing local authorization.
122
+ throw new bearer_challenge_1.InsufficientScopeException(admissionScope);
123
+ }
124
+ const environment = this.profiles.profile.environment;
125
+ let resolution;
126
+ try {
127
+ resolution = await this.resolver.resolve(identity);
128
+ }
129
+ catch (error) {
130
+ // An HttpException is a decision already taken below us; it is neither
131
+ // the store nor a bug, and it must reach the caller with its own status.
132
+ if (error instanceof common_1.HttpException)
133
+ throw error;
134
+ if (error instanceof principal_resolver_1.PrincipalStoreUnavailableError) {
135
+ // The line names what actually failed (the cause's class), not the
136
+ // wrapper; the driver's message travels in the stack, never on the
137
+ // key=value line.
138
+ this.logFailure('authorization store unavailable', 'auth_store_unavailable', error.causeName, error.causeStack);
139
+ throw new common_1.ServiceUnavailableException('authorization store unavailable');
140
+ }
141
+ const errorName = error instanceof Error && error.name ? error.name : typeof error;
142
+ const stack = error instanceof Error ? error.stack : undefined;
143
+ // A bug: rethrow unchanged so Nest answers 500 and the error keeps its
144
+ // own name in the exception filter.
145
+ this.logFailure('authorization load failed', 'auth_store_error', errorName, stack);
146
+ throw error;
147
+ }
148
+ if (!resolution.ok) {
149
+ // The reason is logged for the operator and NOT returned.
150
+ this.logDecision('refused', identity.clientId, environment, resolution);
151
+ throw new common_1.ForbiddenException(this.signetOptions.principalRefusalMessage ??
152
+ 'this identity holds no authorization in this service');
153
+ }
154
+ this.logDecision('authorized', identity.clientId, environment, resolution);
155
+ request[this.signetOptions.requestPrincipalKey] = resolution.principal;
156
+ return true;
157
+ }
158
+ // The one rendering of this guard's authorization DECISION: the line that
159
+ // lets a request through and the line that refuses one, so their field set
160
+ // and its order cannot drift apart -- metric, reason, the resolver's
161
+ // logFields in the order given, clientId, environment.
162
+ //
163
+ // What these lines disclose about the caller: the client id (software, not
164
+ // a person; a registration identifier, not a credential) and whatever the
165
+ // resolver chose to put in `logFields`. No `sub`, no issuer.
166
+ //
167
+ // Levels: a refusal is a `warn`, an authorization a `log` (info). One line
168
+ // per authorized request is the price of having any record of which client
169
+ // acted; it is paid deliberately, because the alternative is no record.
170
+ logDecision(outcome, clientId, environment, resolution) {
171
+ const consumerFields = Object.entries(resolution.logFields ?? {});
172
+ for (const [key] of consumerFields) {
173
+ if (RESERVED_LOG_KEYS.has(key)) {
174
+ // A programming error in the resolver, not a decision: surfaces as
175
+ // a 500 under its own name rather than a forged log line.
176
+ throw new Error(`resolver logFields must not use the reserved key ${key}`);
177
+ }
178
+ }
179
+ const pairs = [
180
+ ['reason', resolution.ok ? 'none' : resolution.reason],
181
+ ...consumerFields,
182
+ ['clientId', clientId],
183
+ ['environment', environment],
184
+ ];
185
+ const rendered = pairs
186
+ .map(([key, value]) => `${(0, log_sanitise_1.sanitiseLogToken)(key)}=${(0, log_sanitise_1.sanitiseLogToken)(value)}`)
187
+ .join(' ');
188
+ if (outcome === 'refused') {
189
+ this.logger.warn(`signet principal refused: metric=signet_principal_refused ${rendered}`);
190
+ return;
191
+ }
192
+ this.logger.log(`signet principal authorized: metric=signet_principal_authorized ${rendered}`);
193
+ }
194
+ // The one rendering of this guard's failure lines. Only the error's class
195
+ // name goes into the key=value line: the driver's message can carry the
196
+ // DSN or the SQL, so it travels in the stack as the SECOND argument, where
197
+ // a structured logger renders it after the filterable fields.
198
+ logFailure(message, metric, errorName, stack) {
199
+ this.logger.error(`${message}: metric=${metric} errorName=${(0, log_sanitise_1.sanitiseLogToken)(errorName)}`, stack);
200
+ }
201
+ };
202
+ exports.SignetBearerGuard = SignetBearerGuard;
203
+ exports.SignetBearerGuard = SignetBearerGuard = __decorate([
204
+ (0, common_1.Injectable)(),
205
+ requirePrincipalResolver(),
206
+ __param(0, (0, common_1.Inject)(principal_resolver_1.SIGNET_PRINCIPAL_RESOLVER)),
207
+ __param(2, (0, common_1.Inject)(options_1.SIGNET_INTEGRATION_OPTIONS)),
208
+ __metadata("design:paramtypes", [Object, deployment_profile_1.SignetDeploymentProfileService, Object, core_1.Reflector])
209
+ ], SignetBearerGuard);
210
+ //# sourceMappingURL=guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export { bearerChallenge, carriesScopeChallenge, type ChallengeDecision, challengeFor, insufficientScopeChallenge, InsufficientScopeException, isResourceRequest, protectedResourceMetadataPath, protectedResourceMetadataUrl, type ScopeChallengeCarrier, } from './bearer-challenge';
2
+ export { BearerChallengeFilter } from './bearer-challenge.filter';
3
+ export { type ChannelFlags, type JwtSettings, readChannelFlags, readSignetAuthConfig, type SignetAuthConfig, type SignetEnvOptions, } from './config';
4
+ export { type DeploymentProfile, type DeploymentProfileInput, type DeploymentProfileResolution, resolveDeploymentProfile, SignetDeploymentProfileService, } from './deployment-profile';
5
+ export { SignetBearerGuard } from './guard';
6
+ export { type JwtRejection, JwtRejectionEnum, JwtVerifier, REMOTE_JWKS_OPTIONS, type VerifiedSignetIdentity, type VerifyResult, } from './jwt-verifier';
7
+ export { type ResolverProvider, SignetIntegrationModule, type SignetIntegrationModuleOptions, } from './module';
8
+ export { DEVELOPMENT_ENVIRONMENT, SIGNET_INTEGRATION_OPTIONS, type SignetDeployedProfile, type SignetDevelopmentProfile, type SignetEnvNames, type SignetIntegrationOptions, } from './options';
9
+ export { createSignetPrincipalDecorator } from './principal.decorator';
10
+ export { type PrincipalResolution, PrincipalStoreUnavailableError, SIGNET_PRINCIPAL_RESOLVER, type SignetPrincipalResolver, } from './principal-resolver';
11
+ export { createProtectedResourceController, type ProtectedResourceMetadata, } from './protected-resource.controller';
12
+ export { IS_PUBLIC_ROUTE, Public } from './public.decorator';
13
+ export { createScopeVocabulary, type ScopeVocabulary, type ScopeVocabularyInput, type TokenScopeRead, } from './scope-vocabulary';
14
+ export { bearerToken, SIGNET_JWT_STRATEGY, SignetJwtStrategy, } from './strategy';
15
+ export { validateSignetIntegrationOptions } from './validate-options';
package/dist/index.js ADDED
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateSignetIntegrationOptions = exports.SignetJwtStrategy = exports.SIGNET_JWT_STRATEGY = exports.bearerToken = exports.createScopeVocabulary = exports.Public = exports.IS_PUBLIC_ROUTE = exports.createProtectedResourceController = exports.SIGNET_PRINCIPAL_RESOLVER = exports.PrincipalStoreUnavailableError = exports.createSignetPrincipalDecorator = exports.SIGNET_INTEGRATION_OPTIONS = exports.DEVELOPMENT_ENVIRONMENT = exports.SignetIntegrationModule = exports.REMOTE_JWKS_OPTIONS = exports.JwtVerifier = exports.JwtRejectionEnum = exports.SignetBearerGuard = exports.SignetDeploymentProfileService = exports.resolveDeploymentProfile = exports.readSignetAuthConfig = exports.readChannelFlags = exports.BearerChallengeFilter = exports.protectedResourceMetadataUrl = exports.protectedResourceMetadataPath = exports.isResourceRequest = exports.InsufficientScopeException = exports.insufficientScopeChallenge = exports.challengeFor = exports.carriesScopeChallenge = exports.bearerChallenge = void 0;
4
+ var bearer_challenge_1 = require("./bearer-challenge");
5
+ Object.defineProperty(exports, "bearerChallenge", { enumerable: true, get: function () { return bearer_challenge_1.bearerChallenge; } });
6
+ Object.defineProperty(exports, "carriesScopeChallenge", { enumerable: true, get: function () { return bearer_challenge_1.carriesScopeChallenge; } });
7
+ Object.defineProperty(exports, "challengeFor", { enumerable: true, get: function () { return bearer_challenge_1.challengeFor; } });
8
+ Object.defineProperty(exports, "insufficientScopeChallenge", { enumerable: true, get: function () { return bearer_challenge_1.insufficientScopeChallenge; } });
9
+ Object.defineProperty(exports, "InsufficientScopeException", { enumerable: true, get: function () { return bearer_challenge_1.InsufficientScopeException; } });
10
+ Object.defineProperty(exports, "isResourceRequest", { enumerable: true, get: function () { return bearer_challenge_1.isResourceRequest; } });
11
+ Object.defineProperty(exports, "protectedResourceMetadataPath", { enumerable: true, get: function () { return bearer_challenge_1.protectedResourceMetadataPath; } });
12
+ Object.defineProperty(exports, "protectedResourceMetadataUrl", { enumerable: true, get: function () { return bearer_challenge_1.protectedResourceMetadataUrl; } });
13
+ var bearer_challenge_filter_1 = require("./bearer-challenge.filter");
14
+ Object.defineProperty(exports, "BearerChallengeFilter", { enumerable: true, get: function () { return bearer_challenge_filter_1.BearerChallengeFilter; } });
15
+ var config_1 = require("./config");
16
+ Object.defineProperty(exports, "readChannelFlags", { enumerable: true, get: function () { return config_1.readChannelFlags; } });
17
+ Object.defineProperty(exports, "readSignetAuthConfig", { enumerable: true, get: function () { return config_1.readSignetAuthConfig; } });
18
+ var deployment_profile_1 = require("./deployment-profile");
19
+ Object.defineProperty(exports, "resolveDeploymentProfile", { enumerable: true, get: function () { return deployment_profile_1.resolveDeploymentProfile; } });
20
+ Object.defineProperty(exports, "SignetDeploymentProfileService", { enumerable: true, get: function () { return deployment_profile_1.SignetDeploymentProfileService; } });
21
+ var guard_1 = require("./guard");
22
+ Object.defineProperty(exports, "SignetBearerGuard", { enumerable: true, get: function () { return guard_1.SignetBearerGuard; } });
23
+ var jwt_verifier_1 = require("./jwt-verifier");
24
+ Object.defineProperty(exports, "JwtRejectionEnum", { enumerable: true, get: function () { return jwt_verifier_1.JwtRejectionEnum; } });
25
+ Object.defineProperty(exports, "JwtVerifier", { enumerable: true, get: function () { return jwt_verifier_1.JwtVerifier; } });
26
+ Object.defineProperty(exports, "REMOTE_JWKS_OPTIONS", { enumerable: true, get: function () { return jwt_verifier_1.REMOTE_JWKS_OPTIONS; } });
27
+ var module_1 = require("./module");
28
+ Object.defineProperty(exports, "SignetIntegrationModule", { enumerable: true, get: function () { return module_1.SignetIntegrationModule; } });
29
+ var options_1 = require("./options");
30
+ Object.defineProperty(exports, "DEVELOPMENT_ENVIRONMENT", { enumerable: true, get: function () { return options_1.DEVELOPMENT_ENVIRONMENT; } });
31
+ Object.defineProperty(exports, "SIGNET_INTEGRATION_OPTIONS", { enumerable: true, get: function () { return options_1.SIGNET_INTEGRATION_OPTIONS; } });
32
+ var principal_decorator_1 = require("./principal.decorator");
33
+ Object.defineProperty(exports, "createSignetPrincipalDecorator", { enumerable: true, get: function () { return principal_decorator_1.createSignetPrincipalDecorator; } });
34
+ var principal_resolver_1 = require("./principal-resolver");
35
+ Object.defineProperty(exports, "PrincipalStoreUnavailableError", { enumerable: true, get: function () { return principal_resolver_1.PrincipalStoreUnavailableError; } });
36
+ Object.defineProperty(exports, "SIGNET_PRINCIPAL_RESOLVER", { enumerable: true, get: function () { return principal_resolver_1.SIGNET_PRINCIPAL_RESOLVER; } });
37
+ var protected_resource_controller_1 = require("./protected-resource.controller");
38
+ Object.defineProperty(exports, "createProtectedResourceController", { enumerable: true, get: function () { return protected_resource_controller_1.createProtectedResourceController; } });
39
+ var public_decorator_1 = require("./public.decorator");
40
+ Object.defineProperty(exports, "IS_PUBLIC_ROUTE", { enumerable: true, get: function () { return public_decorator_1.IS_PUBLIC_ROUTE; } });
41
+ Object.defineProperty(exports, "Public", { enumerable: true, get: function () { return public_decorator_1.Public; } });
42
+ var scope_vocabulary_1 = require("./scope-vocabulary");
43
+ Object.defineProperty(exports, "createScopeVocabulary", { enumerable: true, get: function () { return scope_vocabulary_1.createScopeVocabulary; } });
44
+ var strategy_1 = require("./strategy");
45
+ Object.defineProperty(exports, "bearerToken", { enumerable: true, get: function () { return strategy_1.bearerToken; } });
46
+ Object.defineProperty(exports, "SIGNET_JWT_STRATEGY", { enumerable: true, get: function () { return strategy_1.SIGNET_JWT_STRATEGY; } });
47
+ Object.defineProperty(exports, "SignetJwtStrategy", { enumerable: true, get: function () { return strategy_1.SignetJwtStrategy; } });
48
+ var validate_options_1 = require("./validate-options");
49
+ Object.defineProperty(exports, "validateSignetIntegrationOptions", { enumerable: true, get: function () { return validate_options_1.validateSignetIntegrationOptions; } });
50
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uDAW4B;AAV1B,mHAAA,eAAe,OAAA;AACf,yHAAA,qBAAqB,OAAA;AAErB,gHAAA,YAAY,OAAA;AACZ,8HAAA,0BAA0B,OAAA;AAC1B,8HAAA,0BAA0B,OAAA;AAC1B,qHAAA,iBAAiB,OAAA;AACjB,iIAAA,6BAA6B,OAAA;AAC7B,gIAAA,4BAA4B,OAAA;AAG9B,qEAAkE;AAAzD,gIAAA,qBAAqB,OAAA;AAC9B,mCAOkB;AAJhB,0GAAA,gBAAgB,OAAA;AAChB,8GAAA,oBAAoB,OAAA;AAItB,2DAM8B;AAF5B,8HAAA,wBAAwB,OAAA;AACxB,oIAAA,8BAA8B,OAAA;AAEhC,iCAA4C;AAAnC,0GAAA,iBAAiB,OAAA;AAC1B,+CAOwB;AALtB,gHAAA,gBAAgB,OAAA;AAChB,2GAAA,WAAW,OAAA;AACX,mHAAA,mBAAmB,OAAA;AAIrB,mCAIkB;AAFhB,iHAAA,uBAAuB,OAAA;AAGzB,qCAOmB;AANjB,kHAAA,uBAAuB,OAAA;AACvB,qHAAA,0BAA0B,OAAA;AAM5B,6DAAuE;AAA9D,qIAAA,8BAA8B,OAAA;AACvC,2DAK8B;AAH5B,oIAAA,8BAA8B,OAAA;AAC9B,+HAAA,yBAAyB,OAAA;AAG3B,iFAGyC;AAFvC,kJAAA,iCAAiC,OAAA;AAGnC,uDAA6D;AAApD,mHAAA,eAAe,OAAA;AAAE,0GAAA,MAAM,OAAA;AAChC,uDAK4B;AAJ1B,yHAAA,qBAAqB,OAAA;AAKvB,uCAIoB;AAHlB,uGAAA,WAAW,OAAA;AACX,+GAAA,mBAAmB,OAAA;AACnB,6GAAA,iBAAiB,OAAA;AAEnB,uDAAsE;AAA7D,oIAAA,gCAAgC,OAAA"}
@@ -0,0 +1,36 @@
1
+ import { type JWTPayload } from 'jose';
2
+ import { type JwtSettings } from './config';
3
+ export declare const REMOTE_JWKS_OPTIONS: {
4
+ readonly cacheMaxAge: 600000;
5
+ readonly cooldownDuration: 30000;
6
+ readonly timeoutDuration: 3000;
7
+ };
8
+ export interface VerifiedSignetIdentity {
9
+ readonly claims: Readonly<JWTPayload>;
10
+ readonly clientId: string;
11
+ readonly issuer: string;
12
+ readonly scopes: readonly string[];
13
+ readonly subject: string;
14
+ }
15
+ export declare const JwtRejectionEnum: {
16
+ readonly BAD_SCOPE: "ERR_JWT_BAD_SCOPE";
17
+ readonly JWKS_PARSE: "ERR_JOSE_GENERIC:jwks_parse";
18
+ readonly JWKS_STATUS: "ERR_JOSE_GENERIC:jwks_status";
19
+ readonly NO_CLIENT_ID: "ERR_JWT_NO_CLIENT_ID";
20
+ readonly NO_EXP: "ERR_JWT_NO_EXP";
21
+ readonly NO_SUB: "ERR_JWT_NO_SUB";
22
+ };
23
+ export type JwtRejection = (typeof JwtRejectionEnum)[keyof typeof JwtRejectionEnum];
24
+ export type VerifyResult = {
25
+ ok: false;
26
+ reason: string;
27
+ } | {
28
+ ok: true;
29
+ identity: VerifiedSignetIdentity;
30
+ };
31
+ export declare class JwtVerifier {
32
+ private readonly settings;
33
+ private readonly keys;
34
+ constructor(settings: JwtSettings);
35
+ verify(token: string): Promise<VerifyResult>;
36
+ }
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JwtVerifier = exports.JwtRejectionEnum = exports.REMOTE_JWKS_OPTIONS = void 0;
4
+ const jose_1 = require("jose");
5
+ // Asymmetric signatures only. Allowing HS* opens alg confusion: an attacker
6
+ // signs with our PUBLIC key bytes as the HMAC secret, and a verifier that
7
+ // follows the header's alg accepts it. jose's JWKS path already refuses
8
+ // non-RS/PS/ES/Ed algorithms and only imports public keys, but the keys
9
+ // arrive from a remote endpoint rather than from configuration we read, so
10
+ // the explicit allowlist stays as the second, stated line.
11
+ const ASYMMETRIC_ALGORITHMS = [
12
+ 'RS256',
13
+ 'RS384',
14
+ 'RS512',
15
+ 'PS256',
16
+ 'PS384',
17
+ 'PS512',
18
+ 'ES256',
19
+ 'ES384',
20
+ 'ES512',
21
+ 'EdDSA',
22
+ ];
23
+ // The remote JWKS options, spelled out rather than left to jose's defaults so
24
+ // the contract is fixed. A longer cooldownDuration only delays the refetch an
25
+ // unknown kid triggers after a rotation, and buys no failure backoff -- a
26
+ // failed fetch clears the pending fetch and the next request tries again
27
+ // regardless.
28
+ exports.REMOTE_JWKS_OPTIONS = {
29
+ cacheMaxAge: 600_000,
30
+ cooldownDuration: 30_000,
31
+ timeoutDuration: 3_000,
32
+ };
33
+ // This package's own rejection codes, alongside the ERR_* codes jose throws.
34
+ exports.JwtRejectionEnum = {
35
+ BAD_SCOPE: 'ERR_JWT_BAD_SCOPE',
36
+ JWKS_PARSE: 'ERR_JOSE_GENERIC:jwks_parse',
37
+ JWKS_STATUS: 'ERR_JOSE_GENERIC:jwks_status',
38
+ NO_CLIENT_ID: 'ERR_JWT_NO_CLIENT_ID',
39
+ NO_EXP: 'ERR_JWT_NO_EXP',
40
+ NO_SUB: 'ERR_JWT_NO_SUB',
41
+ };
42
+ // jose reports both JWKS transport failures -- a non-200 status and an
43
+ // unparseable body -- as JOSEError with the same ERR_JOSE_GENERIC code; only
44
+ // the message tells them apart, and an operator reading logs during an
45
+ // outage needs to.
46
+ function joseRejection(error) {
47
+ if (error.code !== 'ERR_JOSE_GENERIC')
48
+ return error.code;
49
+ if (error.message.includes('Expected 200 OK')) {
50
+ return exports.JwtRejectionEnum.JWKS_STATUS;
51
+ }
52
+ if (error.message.includes('Failed to parse')) {
53
+ return exports.JwtRejectionEnum.JWKS_PARSE;
54
+ }
55
+ return error.code;
56
+ }
57
+ // Hydra's JWT access tokens carry the granted scopes as `scp` (an array);
58
+ // RFC 9068 §2.2.3 spells the same thing `scope` (a space-delimited string).
59
+ // Both are read. Neither present is an EMPTY scope set, which the guard
60
+ // refuses with a 403 for lacking the admission scope; either present with the
61
+ // wrong shape is null, a contract violation the caller answers with 401.
62
+ function scopesOf(payload) {
63
+ const { scope, scp } = payload;
64
+ const scopes = [];
65
+ if (scope !== undefined) {
66
+ if (typeof scope !== 'string')
67
+ return null;
68
+ scopes.push(...scope.split(' ').filter((value) => value !== ''));
69
+ }
70
+ if (scp !== undefined) {
71
+ if (!Array.isArray(scp))
72
+ return null;
73
+ for (const value of scp) {
74
+ if (typeof value !== 'string')
75
+ return null;
76
+ scopes.push(value);
77
+ }
78
+ }
79
+ return scopes;
80
+ }
81
+ // Verifies a Signet access token against the trusted issuer's JWKS and the
82
+ // deployment's canonical resource.
83
+ //
84
+ // Returns a result rather than throwing: the caller logs the reason and
85
+ // answers a uniform 401, so a rejection never tells the client WHICH check
86
+ // failed. Key fetch failures land in the same catch -- unreachable JWKS
87
+ // refuses, never admits.
88
+ //
89
+ // One instance for the life of the process: the remote key set's cache,
90
+ // cooldown and pending-fetch state live on it, so constructing one per
91
+ // request would refetch the whole JWKS on every request and defeat the
92
+ // cache.
93
+ class JwtVerifier {
94
+ settings;
95
+ keys;
96
+ constructor(settings) {
97
+ this.settings = settings;
98
+ this.keys = (0, jose_1.createRemoteJWKSet)(new URL(settings.jwksUri), exports.REMOTE_JWKS_OPTIONS);
99
+ }
100
+ async verify(token) {
101
+ let payload;
102
+ try {
103
+ // issuer / audience / exp / nbf are jose's. audience accepts a string
104
+ // or an array containing the expected value; the issuer's fixed client
105
+ // policy is what keeps a token single-audience.
106
+ ({ payload } = await (0, jose_1.jwtVerify)(token, this.keys, {
107
+ algorithms: ASYMMETRIC_ALGORITHMS,
108
+ audience: this.settings.audience,
109
+ clockTolerance: this.settings.clockToleranceS,
110
+ issuer: this.settings.issuer,
111
+ }));
112
+ }
113
+ catch (error) {
114
+ if (error instanceof jose_1.errors.JOSEError) {
115
+ return { ok: false, reason: joseRejection(error) };
116
+ }
117
+ // Errors from the JWKS fetch that are not jose's own -- Node system
118
+ // errors (ECONNREFUSED, ENOTFOUND, ETIMEDOUT, ...) and a key that Node
119
+ // cannot import (crypto's ERR_CRYPTO_* codes) -- carry a string code and
120
+ // refuse like any other unusable issuer. Matched by shape: Node creates
121
+ // them outside a test runner's vm realm, where instanceof Error is
122
+ // false.
123
+ const { code } = (error ?? {});
124
+ if (typeof code === 'string')
125
+ return { ok: false, reason: code };
126
+ // Anything else is a defect in this process, not a bad token: it must
127
+ // surface as a 500, not hide behind a 401.
128
+ throw error;
129
+ }
130
+ // jose does not require exp: a token without one never expires, which
131
+ // is a long-lived credential minted by omission.
132
+ if (typeof payload.exp !== 'number') {
133
+ return { ok: false, reason: exports.JwtRejectionEnum.NO_EXP };
134
+ }
135
+ if (typeof payload.sub !== 'string' || payload.sub.length === 0) {
136
+ return { ok: false, reason: exports.JwtRejectionEnum.NO_SUB };
137
+ }
138
+ // RFC 9068 §2.2 makes client_id a required claim of a JWT access token
139
+ // and Signet issues it on every token, dynamically registered clients
140
+ // included -- so a token without one is not the shape this contract
141
+ // accepts, and its absence is an access-token contract failure (401). It
142
+ // is NOT a lookup key: the guard logs it as the software that presented
143
+ // the credential.
144
+ if (typeof payload.client_id !== 'string' || payload.client_id === '') {
145
+ return { ok: false, reason: exports.JwtRejectionEnum.NO_CLIENT_ID };
146
+ }
147
+ const scopes = scopesOf(payload);
148
+ if (scopes === null) {
149
+ return { ok: false, reason: exports.JwtRejectionEnum.BAD_SCOPE };
150
+ }
151
+ // iat is deliberately not required and no maxTokenAge is applied.
152
+ // Business roles the token might carry are ignored here: authorization
153
+ // is the consumer's resolver's alone.
154
+ return {
155
+ identity: {
156
+ claims: Object.freeze(payload),
157
+ clientId: payload.client_id,
158
+ issuer: this.settings.issuer,
159
+ scopes,
160
+ subject: payload.sub,
161
+ },
162
+ ok: true,
163
+ };
164
+ }
165
+ }
166
+ exports.JwtVerifier = JwtVerifier;
167
+ //# sourceMappingURL=jwt-verifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt-verifier.js","sourceRoot":"","sources":["../src/jwt-verifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function sanitiseLogToken(value: string): string;
2
+ export declare const REFUSAL_ROUTE_MAX = 300;
3
+ export declare function truncate(value: string, max: number): string;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.REFUSAL_ROUTE_MAX = void 0;
4
+ exports.sanitiseLogToken = sanitiseLogToken;
5
+ exports.truncate = truncate;
6
+ // Strip everything that could break OUT of one field of an unquoted
7
+ // "key=value key=value" log record: C0 controls and DEL, all whitespace (the
8
+ // field separator), "=" (the key/value separator), and the double quote and
9
+ // backslash that consumers which do parse quoted values use for grouping and
10
+ // escaping. Applied to the values a caller chose or could influence --
11
+ // reasons, client ids, routes.
12
+ function sanitiseLogToken(value) {
13
+ // eslint-disable-next-line no-control-regex
14
+ return value.replace(/[\s\x00-\x1f\x7f="\\]/g, '_');
15
+ }
16
+ // Longest `route=` a refusal line will carry.
17
+ exports.REFUSAL_ROUTE_MAX = 300;
18
+ // Clips a value to `max` characters and MARKS THE CUT, so a clipped value
19
+ // cannot be read as a whole one.
20
+ function truncate(value, max) {
21
+ return value.length <= max ? value : `${value.slice(0, max)}…(truncated)`;
22
+ }
23
+ //# sourceMappingURL=log-sanitise.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-sanitise.js","sourceRoot":"","sources":["../src/log-sanitise.ts"],"names":[],"mappings":";;;AAMA,4CAGC;AAOD,4BAEC;AAlBD,oEAAoE;AACpE,6EAA6E;AAC7E,4EAA4E;AAC5E,6EAA6E;AAC7E,uEAAuE;AACvE,+BAA+B;AAC/B,SAAgB,gBAAgB,CAAC,KAAa;IAC5C,4CAA4C;IAC5C,OAAO,KAAK,CAAC,OAAO,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAC;AACtD,CAAC;AAED,8CAA8C;AACjC,QAAA,iBAAiB,GAAG,GAAG,CAAC;AAErC,0EAA0E;AAC1E,iCAAiC;AACjC,SAAgB,QAAQ,CAAC,KAAa,EAAE,GAAW;IACjD,OAAO,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,cAAc,CAAC;AAC5E,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { type DynamicModule, type ExistingProvider, type FactoryProvider, type Type, type ValueProvider } from '@nestjs/common';
2
+ import { type SignetIntegrationOptions } from './options';
3
+ import { type SignetPrincipalResolver } from './principal-resolver';
4
+ export type ResolverProvider = Omit<ExistingProvider<SignetPrincipalResolver>, 'provide'> | Omit<FactoryProvider<SignetPrincipalResolver>, 'provide'> | Omit<ValueProvider<SignetPrincipalResolver>, 'provide'> | Type<SignetPrincipalResolver>;
5
+ export interface SignetIntegrationModuleOptions {
6
+ readonly imports?: DynamicModule['imports'];
7
+ readonly options: SignetIntegrationOptions;
8
+ readonly resolver: ResolverProvider;
9
+ }
10
+ export declare class SignetIntegrationModule {
11
+ static forRoot(input: SignetIntegrationModuleOptions): DynamicModule;
12
+ }
package/dist/module.js ADDED
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var SignetIntegrationModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.SignetIntegrationModule = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const deployment_profile_1 = require("./deployment-profile");
13
+ const guard_1 = require("./guard");
14
+ const options_1 = require("./options");
15
+ const principal_resolver_1 = require("./principal-resolver");
16
+ const strategy_1 = require("./strategy");
17
+ const validate_options_1 = require("./validate-options");
18
+ // Wires the Bearer channel: options behind their token, the consumer's
19
+ // resolver behind its token, the deployment profile, the Passport strategy
20
+ // (which registers itself by name in its constructor, so it must be a
21
+ // provider) and the guard. Exports everything a consumer's own auth module
22
+ // re-exports or a dispatcher injects.
23
+ //
24
+ // NOT here: the metadata controller (createProtectedResourceController --
25
+ // the consumer declares it in the module of the process that serves the
26
+ // resource), the exception filter (BearerChallengeFilter as APP_FILTER, or
27
+ // the consumer's own filter calling challengeFor), and the guard's mounting
28
+ // (APP_GUARD, or inside a consumer's credential dispatcher).
29
+ let SignetIntegrationModule = SignetIntegrationModule_1 = class SignetIntegrationModule {
30
+ static forRoot(input) {
31
+ const resolver = typeof input.resolver === 'function'
32
+ ? { provide: principal_resolver_1.SIGNET_PRINCIPAL_RESOLVER, useClass: input.resolver }
33
+ : { ...input.resolver, provide: principal_resolver_1.SIGNET_PRINCIPAL_RESOLVER };
34
+ return {
35
+ exports: [
36
+ options_1.SIGNET_INTEGRATION_OPTIONS,
37
+ principal_resolver_1.SIGNET_PRINCIPAL_RESOLVER,
38
+ guard_1.SignetBearerGuard,
39
+ deployment_profile_1.SignetDeploymentProfileService,
40
+ strategy_1.SignetJwtStrategy,
41
+ ],
42
+ imports: input.imports ?? [],
43
+ module: SignetIntegrationModule_1,
44
+ providers: [
45
+ {
46
+ provide: options_1.SIGNET_INTEGRATION_OPTIONS,
47
+ useValue: (0, validate_options_1.validateSignetIntegrationOptions)(input.options),
48
+ },
49
+ resolver,
50
+ guard_1.SignetBearerGuard,
51
+ deployment_profile_1.SignetDeploymentProfileService,
52
+ strategy_1.SignetJwtStrategy,
53
+ ],
54
+ };
55
+ }
56
+ };
57
+ exports.SignetIntegrationModule = SignetIntegrationModule;
58
+ exports.SignetIntegrationModule = SignetIntegrationModule = SignetIntegrationModule_1 = __decorate([
59
+ (0, common_1.Module)({})
60
+ ], SignetIntegrationModule);
61
+ //# sourceMappingURL=module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAQwB;AAExB,6DAAsE;AACtE,mCAA4C;AAC5C,uCAGmB;AACnB,6DAG8B;AAC9B,yCAA+C;AAC/C,yDAAsE;AAoBtE,uEAAuE;AACvE,2EAA2E;AAC3E,sEAAsE;AACtE,2EAA2E;AAC3E,sCAAsC;AACtC,EAAE;AACF,0EAA0E;AAC1E,wEAAwE;AACxE,2EAA2E;AAC3E,4EAA4E;AAC5E,6DAA6D;AAEtD,IAAM,uBAAuB,+BAA7B,MAAM,uBAAuB;IAClC,MAAM,CAAC,OAAO,CAAC,KAAqC;QAClD,MAAM,QAAQ,GACZ,OAAO,KAAK,CAAC,QAAQ,KAAK,UAAU;YAClC,CAAC,CAAC,EAAE,OAAO,EAAE,8CAAyB,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE;YAClE,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,8CAAyB,EAAE,CAAC;QAChE,OAAO;YACL,OAAO,EAAE;gBACP,oCAA0B;gBAC1B,8CAAyB;gBACzB,yBAAiB;gBACjB,mDAA8B;gBAC9B,4BAAiB;aAClB;YACD,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;YAC5B,MAAM,EAAE,yBAAuB;YAC/B,SAAS,EAAE;gBACT;oBACE,OAAO,EAAE,oCAA0B;oBACnC,QAAQ,EAAE,IAAA,mDAAgC,EAAC,KAAK,CAAC,OAAO,CAAC;iBAC1D;gBACD,QAAQ;gBACR,yBAAiB;gBACjB,mDAA8B;gBAC9B,4BAAiB;aAClB;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AA5BY,0DAAuB;kCAAvB,uBAAuB;IADnC,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,uBAAuB,CA4BnC"}