@argos-js/auth 0.0.0-stage → 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.
- package/LICENSE +21 -0
- package/README.md +13 -2
- package/dist/certificates/cert-parser.d.ts +19 -0
- package/dist/certificates/cert-parser.d.ts.map +1 -0
- package/dist/certificates/cert-parser.js +192 -0
- package/dist/certificates/cert-parser.js.map +1 -0
- package/dist/certificates/cert.types.d.ts +60 -0
- package/dist/certificates/cert.types.d.ts.map +1 -0
- package/dist/certificates/cert.types.js +3 -0
- package/dist/certificates/cert.types.js.map +1 -0
- package/dist/certificates/index.d.ts +5 -0
- package/dist/certificates/index.d.ts.map +1 -0
- package/dist/certificates/index.js +21 -0
- package/dist/certificates/index.js.map +1 -0
- package/dist/certificates/jwks.d.ts +90 -0
- package/dist/certificates/jwks.d.ts.map +1 -0
- package/dist/certificates/jwks.js +180 -0
- package/dist/certificates/jwks.js.map +1 -0
- package/dist/certificates/mtls.guard.d.ts +10 -0
- package/dist/certificates/mtls.guard.d.ts.map +1 -0
- package/dist/certificates/mtls.guard.js +156 -0
- package/dist/certificates/mtls.guard.js.map +1 -0
- package/dist/config.d.ts +33 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +10 -0
- package/dist/config.js.map +1 -0
- package/dist/guards/api-key.guard.d.ts +21 -0
- package/dist/guards/api-key.guard.d.ts.map +1 -0
- package/dist/guards/api-key.guard.js +106 -0
- package/dist/guards/api-key.guard.js.map +1 -0
- package/dist/guards/basic.d.ts +6 -0
- package/dist/guards/basic.d.ts.map +1 -0
- package/dist/guards/basic.guard.d.ts +26 -0
- package/dist/guards/basic.guard.d.ts.map +1 -0
- package/dist/guards/basic.guard.js +123 -0
- package/dist/guards/basic.guard.js.map +1 -0
- package/dist/guards/basic.js +42 -0
- package/dist/guards/basic.js.map +1 -0
- package/dist/guards/guard.interface.d.ts +21 -0
- package/dist/guards/guard.interface.d.ts.map +1 -0
- package/dist/guards/guard.interface.js +3 -0
- package/dist/guards/guard.interface.js.map +1 -0
- package/dist/guards/hmac.guard.d.ts +18 -0
- package/dist/guards/hmac.guard.d.ts.map +1 -0
- package/dist/guards/hmac.guard.js +111 -0
- package/dist/guards/hmac.guard.js.map +1 -0
- package/dist/guards/index.d.ts +8 -0
- package/dist/guards/index.d.ts.map +1 -0
- package/dist/guards/index.js +24 -0
- package/dist/guards/index.js.map +1 -0
- package/dist/guards/jwt.guard.d.ts +17 -0
- package/dist/guards/jwt.guard.d.ts.map +1 -0
- package/dist/guards/jwt.guard.js +92 -0
- package/dist/guards/jwt.guard.js.map +1 -0
- package/dist/hasher/argon2-hasher.d.ts +31 -0
- package/dist/hasher/argon2-hasher.d.ts.map +1 -0
- package/dist/hasher/argon2-hasher.js +114 -0
- package/dist/hasher/argon2-hasher.js.map +1 -0
- package/dist/hasher/hasher.interface.d.ts +22 -0
- package/dist/hasher/hasher.interface.d.ts.map +1 -0
- package/dist/hasher/hasher.interface.js +3 -0
- package/dist/hasher/hasher.interface.js.map +1 -0
- package/dist/hasher/index.d.ts +5 -0
- package/dist/hasher/index.d.ts.map +1 -0
- package/dist/hasher/index.js +21 -0
- package/dist/hasher/index.js.map +1 -0
- package/dist/hasher/password-manager.d.ts +52 -0
- package/dist/hasher/password-manager.d.ts.map +1 -0
- package/dist/hasher/password-manager.js +126 -0
- package/dist/hasher/password-manager.js.map +1 -0
- package/dist/hasher/scrypt-hasher.d.ts +30 -0
- package/dist/hasher/scrypt-hasher.d.ts.map +1 -0
- package/dist/hasher/scrypt-hasher.js +158 -0
- package/dist/hasher/scrypt-hasher.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/auth.middleware.d.ts +42 -0
- package/dist/middleware/auth.middleware.d.ts.map +1 -0
- package/dist/middleware/auth.middleware.js +142 -0
- package/dist/middleware/auth.middleware.js.map +1 -0
- package/dist/middleware/index.d.ts +2 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +18 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/oauth/base.provider.d.ts +27 -0
- package/dist/oauth/base.provider.d.ts.map +1 -0
- package/dist/oauth/base.provider.js +139 -0
- package/dist/oauth/base.provider.js.map +1 -0
- package/dist/oauth/index.d.ts +6 -0
- package/dist/oauth/index.d.ts.map +1 -0
- package/dist/oauth/index.js +22 -0
- package/dist/oauth/index.js.map +1 -0
- package/dist/oauth/oauth-manager.d.ts +41 -0
- package/dist/oauth/oauth-manager.d.ts.map +1 -0
- package/dist/oauth/oauth-manager.js +58 -0
- package/dist/oauth/oauth-manager.js.map +1 -0
- package/dist/oauth/oauth.types.d.ts +55 -0
- package/dist/oauth/oauth.types.d.ts.map +1 -0
- package/dist/oauth/oauth.types.js +3 -0
- package/dist/oauth/oauth.types.js.map +1 -0
- package/dist/oauth/pkce.d.ts +26 -0
- package/dist/oauth/pkce.d.ts.map +1 -0
- package/dist/oauth/pkce.js +136 -0
- package/dist/oauth/pkce.js.map +1 -0
- package/dist/oauth/providers/generic-oidc.provider.d.ts +25 -0
- package/dist/oauth/providers/generic-oidc.provider.d.ts.map +1 -0
- package/dist/oauth/providers/generic-oidc.provider.js +43 -0
- package/dist/oauth/providers/generic-oidc.provider.js.map +1 -0
- package/dist/oauth/providers/github.provider.d.ts +15 -0
- package/dist/oauth/providers/github.provider.d.ts.map +1 -0
- package/dist/oauth/providers/github.provider.js +70 -0
- package/dist/oauth/providers/github.provider.js.map +1 -0
- package/dist/oauth/providers/google.provider.d.ts +12 -0
- package/dist/oauth/providers/google.provider.d.ts.map +1 -0
- package/dist/oauth/providers/google.provider.js +27 -0
- package/dist/oauth/providers/google.provider.js.map +1 -0
- package/dist/oauth/providers/index.d.ts +5 -0
- package/dist/oauth/providers/index.d.ts.map +1 -0
- package/dist/oauth/providers/index.js +21 -0
- package/dist/oauth/providers/index.js.map +1 -0
- package/dist/oauth/providers/microsoft.provider.d.ts +13 -0
- package/dist/oauth/providers/microsoft.provider.d.ts.map +1 -0
- package/dist/oauth/providers/microsoft.provider.js +28 -0
- package/dist/oauth/providers/microsoft.provider.js.map +1 -0
- package/dist/oauth2/client.d.ts +63 -0
- package/dist/oauth2/client.d.ts.map +1 -0
- package/dist/oauth2/client.js +150 -0
- package/dist/oauth2/client.js.map +1 -0
- package/dist/oauth2/index.d.ts +2 -0
- package/dist/oauth2/index.d.ts.map +1 -0
- package/dist/oauth2/index.js +18 -0
- package/dist/oauth2/index.js.map +1 -0
- package/dist/tokens/api-key.d.ts +26 -0
- package/dist/tokens/api-key.d.ts.map +1 -0
- package/dist/tokens/api-key.js +84 -0
- package/dist/tokens/api-key.js.map +1 -0
- package/dist/tokens/index.d.ts +3 -0
- package/dist/tokens/index.d.ts.map +1 -0
- package/dist/tokens/index.js +19 -0
- package/dist/tokens/index.js.map +1 -0
- package/dist/tokens/jwt.d.ts +93 -0
- package/dist/tokens/jwt.d.ts.map +1 -0
- package/dist/tokens/jwt.js +327 -0
- package/dist/tokens/jwt.js.map +1 -0
- package/package.json +38 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Argos-JS Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @argos-js/auth
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Authentication, authorization, JWT token management, password hashing, HTTP Basic Auth, and OAuth2/PKCE utilities for the Argos-JS framework.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔐 **JWT Token Pair Management**: Symmetric (HS256, HS512) and Asymmetric (RS256, Ed25519) token generation and verification.
|
|
8
|
+
- 🔄 **Strict Refresh Token Rotation & Reuse Detection**: Automated token family tracking and replay attack prevention.
|
|
9
|
+
- 🛡️ **Guards & Middlewares**: HTTP Basic Authentication, API Key authentication, Bearer tokens, and OAuth2 PKCE helpers.
|
|
10
|
+
- ⚡ **Near-Cache Acceleration**: Fast token caching and session verification with timing-safe comparisons.
|
|
11
|
+
|
|
12
|
+
## License
|
|
13
|
+
|
|
14
|
+
MIT
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DistinguishedName, ParsedCertificate } from './cert.types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parses a Distinguished Name (DN) string in comma-delimited (RFC 2253 / RFC 4514)
|
|
4
|
+
* or legacy slash-delimited format into a typed DistinguishedName object.
|
|
5
|
+
*/
|
|
6
|
+
export declare function parseDn(dnString: string): DistinguishedName;
|
|
7
|
+
/**
|
|
8
|
+
* Parses a PEM-encoded X.509 certificate using Node's native crypto.X509Certificate.
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseX509Pem(pemString: string): ParsedCertificate;
|
|
11
|
+
/**
|
|
12
|
+
* Parses Node.js tls.PeerCertificate (from req.socket.getPeerCertificate()).
|
|
13
|
+
*/
|
|
14
|
+
export declare function parsePeerCertificate(peerCert: any): ParsedCertificate;
|
|
15
|
+
/**
|
|
16
|
+
* Parses reverse-proxy certificate header values (e.g. Envoy XFCC, Nginx SSL_CLIENT_CERT).
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseProxyClientCertHeader(headerValue: string): ParsedCertificate | null;
|
|
19
|
+
//# sourceMappingURL=cert-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cert-parser.d.ts","sourceRoot":"","sources":["../../src/certificates/cert-parser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE5E;;;GAGG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CAqC3D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,iBAAiB,CAqDjE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,GAAG,GAAG,iBAAiB,CAiCrE;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAyBxF"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.parseDn = parseDn;
|
|
37
|
+
exports.parseX509Pem = parseX509Pem;
|
|
38
|
+
exports.parsePeerCertificate = parsePeerCertificate;
|
|
39
|
+
exports.parseProxyClientCertHeader = parseProxyClientCertHeader;
|
|
40
|
+
const crypto = __importStar(require("node:crypto"));
|
|
41
|
+
/**
|
|
42
|
+
* Parses a Distinguished Name (DN) string in comma-delimited (RFC 2253 / RFC 4514)
|
|
43
|
+
* or legacy slash-delimited format into a typed DistinguishedName object.
|
|
44
|
+
*/
|
|
45
|
+
function parseDn(dnString) {
|
|
46
|
+
const result = {};
|
|
47
|
+
if (!dnString || typeof dnString !== 'string') {
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
const clean = dnString.trim();
|
|
51
|
+
if (clean.startsWith('/')) {
|
|
52
|
+
// Legacy OpenSSL format: /CN=name/O=org/C=US
|
|
53
|
+
const parts = clean.split('/').filter(Boolean);
|
|
54
|
+
for (const part of parts) {
|
|
55
|
+
const idx = part.indexOf('=');
|
|
56
|
+
if (idx !== -1) {
|
|
57
|
+
const key = part.slice(0, idx).trim();
|
|
58
|
+
const val = part.slice(idx + 1).trim();
|
|
59
|
+
result[key] = val;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// Standard RFC format (comma-separated) or Node X509Certificate format (newline-separated)
|
|
65
|
+
const parts = clean.split(/(?:\r?\n|,\s*)(?=[A-Za-z0-9_.-]+=)/);
|
|
66
|
+
for (const part of parts) {
|
|
67
|
+
const idx = part.indexOf('=');
|
|
68
|
+
if (idx !== -1) {
|
|
69
|
+
const key = part.slice(0, idx).trim();
|
|
70
|
+
let val = part.slice(idx + 1).trim();
|
|
71
|
+
// Remove surrounding quotes if present
|
|
72
|
+
if (val.startsWith('"') && val.endsWith('"')) {
|
|
73
|
+
val = val.slice(1, -1);
|
|
74
|
+
}
|
|
75
|
+
result[key] = val;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Parses a PEM-encoded X.509 certificate using Node's native crypto.X509Certificate.
|
|
83
|
+
*/
|
|
84
|
+
function parseX509Pem(pemString) {
|
|
85
|
+
let pem = pemString.trim();
|
|
86
|
+
// If URL-encoded (e.g. from Nginx $ssl_client_cert or Envoy headers)
|
|
87
|
+
if (pem.includes('%20') || pem.includes('%0A') || pem.includes('%2D')) {
|
|
88
|
+
try {
|
|
89
|
+
pem = decodeURIComponent(pem);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// Keep as-is if decoding fails
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Ensure standard PEM headers if missing
|
|
96
|
+
if (!pem.includes('-----BEGIN CERTIFICATE-----')) {
|
|
97
|
+
pem = `-----BEGIN CERTIFICATE-----\n${pem}\n-----END CERTIFICATE-----`;
|
|
98
|
+
}
|
|
99
|
+
const cert = new crypto.X509Certificate(pem);
|
|
100
|
+
const rawSubject = cert.subject;
|
|
101
|
+
const rawIssuer = cert.issuer;
|
|
102
|
+
const subject = parseDn(rawSubject);
|
|
103
|
+
const issuer = parseDn(rawIssuer);
|
|
104
|
+
const validFrom = new Date(cert.validFrom);
|
|
105
|
+
const validTo = new Date(cert.validTo);
|
|
106
|
+
const now = new Date();
|
|
107
|
+
const isExpired = now < validFrom || now > validTo;
|
|
108
|
+
// Check self-signed
|
|
109
|
+
let isSelfSigned = false;
|
|
110
|
+
if (rawSubject === rawIssuer) {
|
|
111
|
+
try {
|
|
112
|
+
isSelfSigned = cert.verify(cert.publicKey);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
isSelfSigned = true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
subject,
|
|
120
|
+
issuer,
|
|
121
|
+
rawSubject,
|
|
122
|
+
rawIssuer,
|
|
123
|
+
commonName: subject.CN,
|
|
124
|
+
serialNumber: cert.serialNumber,
|
|
125
|
+
fingerprint256: cert.fingerprint256.replace(/:/g, '').toLowerCase(),
|
|
126
|
+
validFrom,
|
|
127
|
+
validTo,
|
|
128
|
+
isExpired,
|
|
129
|
+
isSelfSigned,
|
|
130
|
+
rawPem: pem,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Parses Node.js tls.PeerCertificate (from req.socket.getPeerCertificate()).
|
|
135
|
+
*/
|
|
136
|
+
function parsePeerCertificate(peerCert) {
|
|
137
|
+
if (peerCert.raw && Buffer.isBuffer(peerCert.raw)) {
|
|
138
|
+
const cert = new crypto.X509Certificate(peerCert.raw);
|
|
139
|
+
return parseX509Pem(cert.toString());
|
|
140
|
+
}
|
|
141
|
+
const subject = peerCert.subject || {};
|
|
142
|
+
const issuer = peerCert.issuer || {};
|
|
143
|
+
const rawSubject = typeof peerCert.subject === 'string' ? peerCert.subject : JSON.stringify(peerCert.subject);
|
|
144
|
+
const rawIssuer = typeof peerCert.issuer === 'string' ? peerCert.issuer : JSON.stringify(peerCert.issuer);
|
|
145
|
+
const validFrom = peerCert.valid_from ? new Date(peerCert.valid_from) : new Date(0);
|
|
146
|
+
const validTo = peerCert.valid_to ? new Date(peerCert.valid_to) : new Date(0);
|
|
147
|
+
const now = new Date();
|
|
148
|
+
const isExpired = now < validFrom || now > validTo;
|
|
149
|
+
const fingerprint256 = (peerCert.fingerprint256 || peerCert.fingerprint || '')
|
|
150
|
+
.replace(/:/g, '')
|
|
151
|
+
.toLowerCase();
|
|
152
|
+
return {
|
|
153
|
+
subject,
|
|
154
|
+
issuer,
|
|
155
|
+
rawSubject,
|
|
156
|
+
rawIssuer,
|
|
157
|
+
commonName: subject.CN,
|
|
158
|
+
serialNumber: peerCert.serialNumber || '',
|
|
159
|
+
fingerprint256,
|
|
160
|
+
validFrom,
|
|
161
|
+
validTo,
|
|
162
|
+
isExpired,
|
|
163
|
+
isSelfSigned: rawSubject === rawIssuer,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Parses reverse-proxy certificate header values (e.g. Envoy XFCC, Nginx SSL_CLIENT_CERT).
|
|
168
|
+
*/
|
|
169
|
+
function parseProxyClientCertHeader(headerValue) {
|
|
170
|
+
if (!headerValue || typeof headerValue !== 'string') {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
const trimmed = headerValue.trim();
|
|
174
|
+
// Envoy X-Forwarded-Client-Cert: Cert="<url-encoded-pem>";Subject="...";...
|
|
175
|
+
if (trimmed.startsWith('Cert=') || trimmed.includes(';Cert=')) {
|
|
176
|
+
const match = trimmed.match(/Cert="([^"]+)"/i);
|
|
177
|
+
if (match && match[1]) {
|
|
178
|
+
return parseX509Pem(match[1]);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Direct PEM or URL-encoded PEM
|
|
182
|
+
if (trimmed.includes('BEGIN%20CERTIFICATE') || trimmed.includes('BEGIN CERTIFICATE') || trimmed.length > 100) {
|
|
183
|
+
try {
|
|
184
|
+
return parseX509Pem(trimmed);
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
// Fallback
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=cert-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cert-parser.js","sourceRoot":"","sources":["../../src/certificates/cert-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { AuthUser } from '../guards/guard.interface.js';
|
|
2
|
+
export interface DistinguishedName {
|
|
3
|
+
CN?: string;
|
|
4
|
+
O?: string;
|
|
5
|
+
OU?: string;
|
|
6
|
+
L?: string;
|
|
7
|
+
ST?: string;
|
|
8
|
+
C?: string;
|
|
9
|
+
emailAddress?: string;
|
|
10
|
+
[key: string]: string | undefined;
|
|
11
|
+
}
|
|
12
|
+
export interface ParsedCertificate {
|
|
13
|
+
subject: DistinguishedName;
|
|
14
|
+
issuer: DistinguishedName;
|
|
15
|
+
rawSubject: string;
|
|
16
|
+
rawIssuer: string;
|
|
17
|
+
commonName?: string;
|
|
18
|
+
serialNumber: string;
|
|
19
|
+
fingerprint256: string;
|
|
20
|
+
validFrom: Date;
|
|
21
|
+
validTo: Date;
|
|
22
|
+
isExpired: boolean;
|
|
23
|
+
isSelfSigned: boolean;
|
|
24
|
+
rawPem?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface MtlsGuardOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Whitelist of allowed Common Names (CN). If empty, any valid CN is accepted.
|
|
29
|
+
*/
|
|
30
|
+
allowedCommonNames?: string[];
|
|
31
|
+
/**
|
|
32
|
+
* Whitelist of allowed Issuer Common Names or DN strings.
|
|
33
|
+
*/
|
|
34
|
+
allowedIssuers?: string[];
|
|
35
|
+
/**
|
|
36
|
+
* Whether to permit expired certificates (default: false).
|
|
37
|
+
*/
|
|
38
|
+
allowExpired?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Whether to allow self-signed certificates (default: false).
|
|
41
|
+
*/
|
|
42
|
+
allowSelfSigned?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Whether to trust proxy headers (e.g. X-Forwarded-Client-Cert, SSL_CLIENT_S_DN).
|
|
45
|
+
*/
|
|
46
|
+
trustedProxies?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Custom header names when behind reverse proxies (Nginx, Envoy, Traefik, Cloudflare).
|
|
49
|
+
*/
|
|
50
|
+
headerNames?: {
|
|
51
|
+
cert?: string;
|
|
52
|
+
dn?: string;
|
|
53
|
+
verify?: string;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Custom user resolver transforming the validated certificate into an AuthUser.
|
|
57
|
+
*/
|
|
58
|
+
userResolver?: (cert: ParsedCertificate) => Promise<AuthUser | null> | AuthUser | null;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=cert.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cert.types.d.ts","sourceRoot":"","sources":["../../src/certificates/cert.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAE7D,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,IAAI,CAAC;IAChB,OAAO,EAAE,IAAI,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;OAEG;IACH,WAAW,CAAC,EAAE;QACZ,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,QAAQ,GAAG,IAAI,CAAC;CACxF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cert.types.js","sourceRoot":"","sources":["../../src/certificates/cert.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/certificates/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./cert.types.js"), exports);
|
|
18
|
+
__exportStar(require("./cert-parser.js"), exports);
|
|
19
|
+
__exportStar(require("./mtls.guard.js"), exports);
|
|
20
|
+
__exportStar(require("./jwks.js"), exports);
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/certificates/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kDAAgC;AAChC,mDAAiC;AACjC,kDAAgC;AAChC,4CAA0B"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import * as crypto from 'node:crypto';
|
|
2
|
+
import type { ArgosContext } from '@argos-js/net';
|
|
3
|
+
export interface JwkPublicKey {
|
|
4
|
+
kty: 'RSA' | 'OKP' | string;
|
|
5
|
+
use?: 'sig' | 'enc' | string;
|
|
6
|
+
alg?: 'RS256' | 'EdDSA' | string;
|
|
7
|
+
kid: string;
|
|
8
|
+
n?: string;
|
|
9
|
+
e?: string;
|
|
10
|
+
crv?: string;
|
|
11
|
+
x?: string;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
export interface JwksResponse {
|
|
15
|
+
keys: JwkPublicKey[];
|
|
16
|
+
}
|
|
17
|
+
export interface ManagedKey {
|
|
18
|
+
kid: string;
|
|
19
|
+
algorithm: 'RS256' | 'EdDSA';
|
|
20
|
+
publicKey: crypto.KeyObject;
|
|
21
|
+
privateKey?: crypto.KeyObject;
|
|
22
|
+
jwk: JwkPublicKey;
|
|
23
|
+
createdAt: Date;
|
|
24
|
+
expiresAt?: Date;
|
|
25
|
+
}
|
|
26
|
+
export interface JwksManagerOptions {
|
|
27
|
+
keys?: Array<{
|
|
28
|
+
kid: string;
|
|
29
|
+
algorithm: 'RS256' | 'EdDSA';
|
|
30
|
+
publicKey: crypto.KeyObject | string;
|
|
31
|
+
privateKey?: crypto.KeyObject | string;
|
|
32
|
+
isDefaultSigning?: boolean;
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
35
|
+
export declare class JwksManager {
|
|
36
|
+
private keysMap;
|
|
37
|
+
private defaultSigningKid?;
|
|
38
|
+
constructor(options?: JwksManagerOptions);
|
|
39
|
+
/**
|
|
40
|
+
* Adds or registers a public/private key pair to the manager.
|
|
41
|
+
*/
|
|
42
|
+
addKey(options: {
|
|
43
|
+
kid: string;
|
|
44
|
+
algorithm: 'RS256' | 'EdDSA';
|
|
45
|
+
publicKey: crypto.KeyObject | string;
|
|
46
|
+
privateKey?: crypto.KeyObject | string;
|
|
47
|
+
isDefaultSigning?: boolean;
|
|
48
|
+
expiresAt?: Date;
|
|
49
|
+
}): ManagedKey;
|
|
50
|
+
/**
|
|
51
|
+
* Rotates key: Registers a new active signing key while keeping older keys
|
|
52
|
+
* valid for signature verification (zero-downtime rotation).
|
|
53
|
+
*/
|
|
54
|
+
rotateKey(options: {
|
|
55
|
+
kid: string;
|
|
56
|
+
algorithm: 'RS256' | 'EdDSA';
|
|
57
|
+
publicKey: crypto.KeyObject | string;
|
|
58
|
+
privateKey?: crypto.KeyObject | string;
|
|
59
|
+
}): ManagedKey;
|
|
60
|
+
/**
|
|
61
|
+
* Generates the RFC 7517 compliant JWKS JSON document for /.well-known/jwks.json
|
|
62
|
+
*/
|
|
63
|
+
getJwks(): JwksResponse;
|
|
64
|
+
getKey(kid: string): ManagedKey | undefined;
|
|
65
|
+
getSigningKey(): ManagedKey | undefined;
|
|
66
|
+
getAllKeys(): ManagedKey[];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Creates an Argos route handler that serves the /.well-known/jwks.json endpoint.
|
|
70
|
+
*/
|
|
71
|
+
export declare function createJwksHandler(manager: JwksManager): (ctx: ArgosContext) => unknown;
|
|
72
|
+
export interface JwksClientOptions {
|
|
73
|
+
jwksUri: string;
|
|
74
|
+
cacheTtlMs?: number;
|
|
75
|
+
fetcher?: (url: string) => Promise<JwksResponse>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Remote JWKS client with in-memory caching and automatic key fetching.
|
|
79
|
+
*/
|
|
80
|
+
export declare class JwksClient {
|
|
81
|
+
private jwksUri;
|
|
82
|
+
private cacheTtlMs;
|
|
83
|
+
private cachedKeys;
|
|
84
|
+
private lastFetchedAt;
|
|
85
|
+
private fetcher;
|
|
86
|
+
constructor(options: JwksClientOptions);
|
|
87
|
+
private refreshCache;
|
|
88
|
+
getSigningKey(kid: string): Promise<crypto.KeyObject | undefined>;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=jwks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwks.d.ts","sourceRoot":"","sources":["../../src/certificates/jwks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.JwksClient = exports.JwksManager = void 0;
|
|
37
|
+
exports.createJwksHandler = createJwksHandler;
|
|
38
|
+
const crypto = __importStar(require("node:crypto"));
|
|
39
|
+
class JwksManager {
|
|
40
|
+
keysMap = new Map();
|
|
41
|
+
defaultSigningKid;
|
|
42
|
+
constructor(options = {}) {
|
|
43
|
+
if (options.keys) {
|
|
44
|
+
for (const k of options.keys) {
|
|
45
|
+
this.addKey(k);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Adds or registers a public/private key pair to the manager.
|
|
51
|
+
*/
|
|
52
|
+
addKey(options) {
|
|
53
|
+
const pubKeyObj = typeof options.publicKey === 'string'
|
|
54
|
+
? crypto.createPublicKey(options.publicKey)
|
|
55
|
+
: options.publicKey;
|
|
56
|
+
const privKeyObj = options.privateKey
|
|
57
|
+
? typeof options.privateKey === 'string'
|
|
58
|
+
? crypto.createPrivateKey(options.privateKey)
|
|
59
|
+
: options.privateKey
|
|
60
|
+
: undefined;
|
|
61
|
+
// Export public key as JWK using native crypto KeyObject export
|
|
62
|
+
const jwkExport = pubKeyObj.export({ format: 'jwk' });
|
|
63
|
+
const jwk = {
|
|
64
|
+
...jwkExport,
|
|
65
|
+
use: 'sig',
|
|
66
|
+
alg: options.algorithm,
|
|
67
|
+
kid: options.kid,
|
|
68
|
+
};
|
|
69
|
+
const managed = {
|
|
70
|
+
kid: options.kid,
|
|
71
|
+
algorithm: options.algorithm,
|
|
72
|
+
publicKey: pubKeyObj,
|
|
73
|
+
privateKey: privKeyObj,
|
|
74
|
+
jwk,
|
|
75
|
+
createdAt: new Date(),
|
|
76
|
+
expiresAt: options.expiresAt,
|
|
77
|
+
};
|
|
78
|
+
this.keysMap.set(options.kid, managed);
|
|
79
|
+
if (options.isDefaultSigning || !this.defaultSigningKid) {
|
|
80
|
+
this.defaultSigningKid = options.kid;
|
|
81
|
+
}
|
|
82
|
+
return managed;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Rotates key: Registers a new active signing key while keeping older keys
|
|
86
|
+
* valid for signature verification (zero-downtime rotation).
|
|
87
|
+
*/
|
|
88
|
+
rotateKey(options) {
|
|
89
|
+
return this.addKey({
|
|
90
|
+
...options,
|
|
91
|
+
isDefaultSigning: true,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Generates the RFC 7517 compliant JWKS JSON document for /.well-known/jwks.json
|
|
96
|
+
*/
|
|
97
|
+
getJwks() {
|
|
98
|
+
const now = new Date();
|
|
99
|
+
const publicKeys = [];
|
|
100
|
+
for (const key of this.keysMap.values()) {
|
|
101
|
+
if (key.expiresAt && key.expiresAt < now) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
publicKeys.push(key.jwk);
|
|
105
|
+
}
|
|
106
|
+
return { keys: publicKeys };
|
|
107
|
+
}
|
|
108
|
+
getKey(kid) {
|
|
109
|
+
return this.keysMap.get(kid);
|
|
110
|
+
}
|
|
111
|
+
getSigningKey() {
|
|
112
|
+
if (!this.defaultSigningKid)
|
|
113
|
+
return undefined;
|
|
114
|
+
return this.keysMap.get(this.defaultSigningKid);
|
|
115
|
+
}
|
|
116
|
+
getAllKeys() {
|
|
117
|
+
return Array.from(this.keysMap.values());
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
exports.JwksManager = JwksManager;
|
|
121
|
+
/**
|
|
122
|
+
* Creates an Argos route handler that serves the /.well-known/jwks.json endpoint.
|
|
123
|
+
*/
|
|
124
|
+
function createJwksHandler(manager) {
|
|
125
|
+
return (ctx) => {
|
|
126
|
+
return ctx.json(manager.getJwks(), 200, {
|
|
127
|
+
'cache-control': 'public, max-age=3600, stale-while-revalidate=86400',
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Remote JWKS client with in-memory caching and automatic key fetching.
|
|
133
|
+
*/
|
|
134
|
+
class JwksClient {
|
|
135
|
+
jwksUri;
|
|
136
|
+
cacheTtlMs;
|
|
137
|
+
cachedKeys = new Map();
|
|
138
|
+
lastFetchedAt = 0;
|
|
139
|
+
fetcher;
|
|
140
|
+
constructor(options) {
|
|
141
|
+
this.jwksUri = options.jwksUri;
|
|
142
|
+
this.cacheTtlMs = options.cacheTtlMs ?? 600000;
|
|
143
|
+
this.fetcher = options.fetcher ?? (async (url) => {
|
|
144
|
+
const res = await fetch(url);
|
|
145
|
+
if (!res.ok) {
|
|
146
|
+
throw new Error(`Failed to fetch JWKS from ${url}: HTTP ${res.status}`);
|
|
147
|
+
}
|
|
148
|
+
return (await res.json());
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
async refreshCache() {
|
|
152
|
+
const data = await this.fetcher(this.jwksUri);
|
|
153
|
+
this.cachedKeys.clear();
|
|
154
|
+
if (Array.isArray(data.keys)) {
|
|
155
|
+
for (const jwk of data.keys) {
|
|
156
|
+
try {
|
|
157
|
+
const keyObject = crypto.createPublicKey({
|
|
158
|
+
key: jwk,
|
|
159
|
+
format: 'jwk',
|
|
160
|
+
});
|
|
161
|
+
this.cachedKeys.set(jwk.kid, keyObject);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// ignore unsupported or invalid keys
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
this.lastFetchedAt = Date.now();
|
|
169
|
+
}
|
|
170
|
+
async getSigningKey(kid) {
|
|
171
|
+
const now = Date.now();
|
|
172
|
+
const isCacheExpired = now - this.lastFetchedAt > this.cacheTtlMs;
|
|
173
|
+
if (isCacheExpired || !this.cachedKeys.has(kid)) {
|
|
174
|
+
await this.refreshCache();
|
|
175
|
+
}
|
|
176
|
+
return this.cachedKeys.get(kid);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
exports.JwksClient = JwksClient;
|
|
180
|
+
//# sourceMappingURL=jwks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwks.js","sourceRoot":"","sources":["../../src/certificates/jwks.ts"],"names":[],"mappings":"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"}
|