@productcraft/auth-passport 0.2.0 → 0.2.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.
- package/dist/index.cjs +6 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4 -7
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var crypto = require('crypto');
|
|
4
|
+
var module$1 = require('module');
|
|
4
5
|
var jose = require('jose');
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
10
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
11
|
-
});
|
|
7
|
+
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.5.1_postcss@8.5.15_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js
|
|
8
|
+
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
9
|
+
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
12
10
|
function createPassportSecretOrKeyProvider(scope) {
|
|
13
11
|
return (_request, rawJwt, done) => {
|
|
14
12
|
let header;
|
|
@@ -33,7 +31,8 @@ function createPassportSecretOrKeyProvider(scope) {
|
|
|
33
31
|
}
|
|
34
32
|
function loadPassportJwt() {
|
|
35
33
|
try {
|
|
36
|
-
const
|
|
34
|
+
const requireFromHere = module$1.createRequire(importMetaUrl);
|
|
35
|
+
const mod = requireFromHere("passport-jwt");
|
|
37
36
|
return {
|
|
38
37
|
Strategy: mod.Strategy ?? mod.default?.Strategy,
|
|
39
38
|
ExtractJwt: mod.ExtractJwt ?? mod.default?.ExtractJwt
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["decodeProtectedHeader","KeyObject"],"mappings":";;;;;;;;;;;AAsEO,SAAS,kCACd,KAAA,EAC6B;AAC7B,EAAA,OAAO,CAAC,QAAA,EAAU,MAAA,EAAQ,IAAA,KAAS;AACjC,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAA,GAASA,2BAAsB,MAAM,CAAA;AAAA,IACvC,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,GAAG,CAAA;AACR,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,CAAM,IAAA,CAAK,MAAA,CAAO,MAA6B,CAAA,CAAE,IAAA;AAAA,MAC/C,CAAC,SAAA,KAAc;AACb,QAAA,IAAI;AAKF,UAAA,MAAM,SAAA,GAAYC,gBAAA,CAAU,IAAA,CAAK,SAAS,CAAA;AAC1C,UAAA,IAAA,CAAK,MAAM,SAAS,CAAA;AAAA,QACtB,SAAS,GAAA,EAAK;AACZ,UAAA,IAAA,CAAK,GAAG,CAAA;AAAA,QACV;AAAA,MACF,CAAA;AAAA,MACA,CAAC,GAAA,KAAQ,IAAA,CAAK,GAAG;AAAA,KACnB;AAAA,EACF,CAAA;AACF;AA+DA,SAAS,eAAA,GAGP;AACA,EAAA,IAAI;AAEF,IAAA,MAAM,GAAA,GAAM,UAAQ,cAAc,CAAA;AAClC,IAAA,OAAO;AAAA,MACL,QAAA,EAAU,GAAA,CAAI,QAAA,IAAY,GAAA,CAAI,OAAA,EAAS,QAAA;AAAA,MACvC,UAAA,EAAY,GAAA,CAAI,UAAA,IAAc,GAAA,CAAI,OAAA,EAAS;AAAA,KAC7C;AAAA,EACF,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AACF;AAeO,SAAS,qBAAA,CACd,KAAA,EACA,MAAA,EACA,OAAA,GAAwC,EAAC,EACzC;AACA,EAAA,MAAM,cAAc,eAAA,EAAgB;AACpC,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,YAAA,GACnB,KAAA,CAAM,iBACL,KAAA,CAAM,eAAA;AAEX,EAAA,OAAO,IAAI,WAAA,CAAY,QAAA;AAAA,IACrB;AAAA,MACE,cAAA,EACE,OAAA,CAAQ,cAAA,IAAkB,WAAA,CAAY,WAAW,2BAAA,EAA4B;AAAA,MAC/E,mBAAA,EAAqB,kCAAkC,KAAK,CAAA;AAAA,MAC5D,MAAA;AAAA,MACA,UAAU,KAAA,CAAM,gBAAA;AAAA,MAChB,UAAA,EAAY,OAAA,CAAQ,UAAA,IAAc,CAAC,OAAO,CAAA;AAAA,MAC1C,iBAAA,EAAmB,QAAQ,iBAAA,IAAqB;AAAA,KAClD;AAAA,IACA;AAAA,GACF;AACF","file":"index.cjs","sourcesContent":["/**\n * `@productcraft/auth-passport` — passport-jwt adapter for Auth.\n *\n * Install alongside `@productcraft/auth` + `passport-jwt`:\n *\n * ```bash\n * npm install @productcraft/auth @productcraft/auth-passport passport-jwt\n * ```\n *\n * Recommended one-call form:\n *\n * ```ts\n * import passportJwt from \"passport-jwt\";\n * import passport from \"passport\";\n * import { Auth } from \"@productcraft/auth\";\n * import { createAuthJwtStrategy } from \"@productcraft/auth-passport\";\n *\n * const auth = new Auth({ auth: { type: \"apiKey\", key: process.env.PCFT_KEY! } });\n * const scope = auth.consumer(\"my-app-slug\");\n *\n * passport.use(createAuthJwtStrategy(scope, (claims, done) => {\n * // claims is the verified Auth claims object (sub, role, permissions, ...)\n * return done(null, claims);\n * }));\n * ```\n *\n * The helper wires `secretOrKeyProvider` + `issuer` (per-app URL) +\n * `audience` (app slug) + algorithms automatically from the scope.\n *\n * If you need the underlying primitives — to compose with your own\n * options or pass a custom `jwtFromRequest` — use the lower-level\n * `createPassportSecretOrKeyProvider` directly:\n *\n * ```ts\n * new passportJwt.Strategy(\n * {\n * jwtFromRequest: passportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),\n * secretOrKeyProvider: createPassportSecretOrKeyProvider(scope),\n * issuer: scope.acceptedIssuers as string[],\n * audience: scope.expectedAudience,\n * algorithms: [\"RS256\", \"ES256\"],\n * },\n * (payload, done) => done(null, payload),\n * );\n * ```\n */\n\nimport { KeyObject } from \"node:crypto\";\nimport { decodeProtectedHeader, type JWTHeaderParameters } from \"jose\";\n\nimport type { ConsumerScope } from \"@productcraft/auth\";\n\n/**\n * passport-jwt's `secretOrKeyProvider` callback signature. We don't\n * depend on passport-jwt's types directly (to keep it a soft dep),\n * so this is the same shape as `SecretOrKeyProvider` in their typings.\n */\ntype PassportSecretOrKeyProvider = (\n request: unknown,\n rawJwtToken: string,\n done: (err: unknown, secretOrKey?: string | Buffer | KeyObject) => void,\n) => void;\n\n/**\n * Returns a passport-jwt `secretOrKeyProvider` bound to an Auth\n * `ConsumerScope`. Decodes the protected header, looks up the matching\n * key via the scope's JWKS cache, and converts the resulting jose\n * `CryptoKey` into a Node `KeyObject` that `jsonwebtoken` (the library\n * passport-jwt delegates to) accepts.\n */\nexport function createPassportSecretOrKeyProvider(\n scope: ConsumerScope,\n): PassportSecretOrKeyProvider {\n return (_request, rawJwt, done) => {\n let header;\n try {\n header = decodeProtectedHeader(rawJwt);\n } catch (err) {\n done(err);\n return;\n }\n\n scope.jwks.getKey(header as JWTHeaderParameters).then(\n (cryptoKey) => {\n try {\n // `jsonwebtoken` (passport-jwt's verifier) doesn't accept\n // Web Crypto `CryptoKey`, but it does accept Node's\n // `KeyObject`. `KeyObject.from(cryptoKey)` was added in\n // Node 16.6 and is the right adapter.\n const keyObject = KeyObject.from(cryptoKey);\n done(null, keyObject);\n } catch (err) {\n done(err);\n }\n },\n (err) => done(err),\n );\n };\n}\n\n/**\n * Shape of the verified-claims callback passport delegates to once a\n * token passes signature + issuer + audience + expiry checks. Mirrors\n * `passport-jwt`'s own `VerifyCallback` / `VerifyCallbackWithRequest`.\n */\nexport type AuthVerifyCallback = (\n payload: Record<string, unknown>,\n done: (err: unknown, user?: unknown, info?: unknown) => void,\n) => void;\n\n/**\n * Extra options for `createAuthJwtStrategy`. Defaults are the\n * Auth-recommended values; override here if you need a different\n * token source (cookie, custom header, ...), a stricter algorithm\n * allow-list, or want to skip the legacy-issuer acceptance window.\n */\nexport interface CreateAuthJwtStrategyOptions {\n /**\n * Where to read the bearer from. Defaults to\n * `ExtractJwt.fromAuthHeaderAsBearerToken()`. Pass any\n * passport-jwt extractor when you need a different source.\n */\n jwtFromRequest?: (req: unknown) => string | null;\n\n /**\n * JWS algorithms accepted by the underlying verifier. Defaults to\n * the algorithms Auth mints today (`['RS256']`); set explicitly\n * if your app is on a different signing alg or you also accept\n * customer-minted tokens with a different alg.\n */\n algorithms?: string[];\n\n /**\n * Pin only the per-app issuer URL (skip the legacy `'heimdall'`\n * literal). Defaults to `false` — verifying both keeps in-flight\n * tokens minted before the per-app-issuer migration valid. Set to\n * `true` once you're confident all old tokens have expired.\n */\n strictIssuer?: boolean;\n\n /** Whether the request object should be passed to the verify callback. Defaults to `false`. */\n passReqToCallback?: boolean;\n}\n\n/**\n * Constructor signature for `passport-jwt`'s `Strategy`. We don't take\n * a direct dep on passport-jwt to keep it a peer/soft dep — at runtime\n * the caller imports passportJwt and the helper does\n * `new passportJwt.Strategy(...)` via the constructor reference.\n */\nexport interface PassportJwtStrategyCtor {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n new (options: Record<string, unknown>, verify: AuthVerifyCallback): any;\n}\n\n/**\n * Lazy passport-jwt loader. We try to `require('passport-jwt')` from\n * the caller's dep graph at first use. Throws a clear error if it's\n * missing so the user doesn't see a cryptic `Cannot find module`\n * deep in the strategy constructor.\n */\nfunction loadPassportJwt(): {\n Strategy: PassportJwtStrategyCtor;\n ExtractJwt: { fromAuthHeaderAsBearerToken: () => (req: unknown) => string | null };\n} {\n try {\n // dynamic require so passport-jwt stays a peer dep\n const mod = require(\"passport-jwt\");\n return {\n Strategy: mod.Strategy ?? mod.default?.Strategy,\n ExtractJwt: mod.ExtractJwt ?? mod.default?.ExtractJwt,\n };\n } catch {\n throw new Error(\n \"@productcraft/auth-passport: `passport-jwt` is not installed. Run `npm install passport-jwt @types/passport-jwt`.\",\n );\n }\n}\n\n/**\n * Build a fully-configured `passport-jwt` strategy from an Auth\n * `ConsumerScope`. Wires:\n *\n * - `jwtFromRequest` → `ExtractJwt.fromAuthHeaderAsBearerToken()` (override via opts)\n * - `secretOrKeyProvider` → JWKS-backed key resolution via `scope.jwks`\n * - `issuer` → both `scope.expectedIssuer` AND the legacy `'heimdall'` literal (or only the per-app URL if `strictIssuer: true`)\n * - `audience` → `scope.expectedAudience` (the app slug)\n * - `algorithms` → `['RS256']` (override via opts)\n *\n * The verify callback you pass receives the parsed claims after\n * passport-jwt has finished its checks.\n */\nexport function createAuthJwtStrategy(\n scope: ConsumerScope,\n verify: AuthVerifyCallback,\n options: CreateAuthJwtStrategyOptions = {},\n) {\n const passportJwt = loadPassportJwt();\n const issuer = options.strictIssuer\n ? scope.expectedIssuer\n : (scope.acceptedIssuers as string[]);\n\n return new passportJwt.Strategy(\n {\n jwtFromRequest:\n options.jwtFromRequest ?? passportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),\n secretOrKeyProvider: createPassportSecretOrKeyProvider(scope),\n issuer,\n audience: scope.expectedAudience,\n algorithms: options.algorithms ?? [\"RS256\"],\n passReqToCallback: options.passReqToCallback ?? false,\n },\n verify,\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../node_modules/.pnpm/tsup@8.5.1_jiti@2.5.1_postcss@8.5.15_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js","../src/index.ts"],"names":["decodeProtectedHeader","KeyObject","createRequire"],"mappings":";;;;;;;AAKA,IAAM,gBAAA,GAAmB,MACvB,OAAO,QAAA,KAAa,WAAA,GAChB,IAAI,GAAA,CAAI,CAAA,KAAA,EAAQ,UAAU,CAAA,CAAE,CAAA,CAAE,IAAA,GAC7B,QAAA,CAAS,aAAA,IAAiB,QAAA,CAAS,aAAA,CAAc,OAAA,CAAQ,WAAA,EAAY,KAAM,QAAA,GAC1E,QAAA,CAAS,aAAA,CAAc,GAAA,GACvB,IAAI,GAAA,CAAI,SAAA,EAAW,QAAA,CAAS,OAAO,CAAA,CAAE,IAAA;AAEtC,IAAM,gCAAgC,gBAAA,EAAiB;AC2DvD,SAAS,kCACd,KAAA,EAC6B;AAC7B,EAAA,OAAO,CAAC,QAAA,EAAU,MAAA,EAAQ,IAAA,KAAS;AACjC,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAA,GAASA,2BAAsB,MAAM,CAAA;AAAA,IACvC,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,GAAG,CAAA;AACR,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,CAAM,IAAA,CAAK,MAAA,CAAO,MAA6B,CAAA,CAAE,IAAA;AAAA,MAC/C,CAAC,SAAA,KAAc;AACb,QAAA,IAAI;AAKF,UAAA,MAAM,SAAA,GAAYC,gBAAA,CAAU,IAAA,CAAK,SAAS,CAAA;AAC1C,UAAA,IAAA,CAAK,MAAM,SAAS,CAAA;AAAA,QACtB,SAAS,GAAA,EAAK;AACZ,UAAA,IAAA,CAAK,GAAG,CAAA;AAAA,QACV;AAAA,MACF,CAAA;AAAA,MACA,CAAC,GAAA,KAAQ,IAAA,CAAK,GAAG;AAAA,KACnB;AAAA,EACF,CAAA;AACF;AAoEA,SAAS,eAAA,GAGP;AACA,EAAA,IAAI;AAEF,IAAA,MAAM,eAAA,GAAkBC,uBAAc,aAAe,CAAA;AACrD,IAAA,MAAM,GAAA,GAAM,gBAAgB,cAAc,CAAA;AAC1C,IAAA,OAAO;AAAA,MACL,QAAA,EAAU,GAAA,CAAI,QAAA,IAAY,GAAA,CAAI,OAAA,EAAS,QAAA;AAAA,MACvC,UAAA,EAAY,GAAA,CAAI,UAAA,IAAc,GAAA,CAAI,OAAA,EAAS;AAAA,KAC7C;AAAA,EACF,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AACF;AAeO,SAAS,qBAAA,CACd,KAAA,EACA,MAAA,EACA,OAAA,GAAwC,EAAC,EACzC;AACA,EAAA,MAAM,cAAc,eAAA,EAAgB;AACpC,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,YAAA,GACnB,KAAA,CAAM,iBACL,KAAA,CAAM,eAAA;AAEX,EAAA,OAAO,IAAI,WAAA,CAAY,QAAA;AAAA,IACrB;AAAA,MACE,cAAA,EACE,OAAA,CAAQ,cAAA,IAAkB,WAAA,CAAY,WAAW,2BAAA,EAA4B;AAAA,MAC/E,mBAAA,EAAqB,kCAAkC,KAAK,CAAA;AAAA,MAC5D,MAAA;AAAA,MACA,UAAU,KAAA,CAAM,gBAAA;AAAA,MAChB,UAAA,EAAY,OAAA,CAAQ,UAAA,IAAc,CAAC,OAAO,CAAA;AAAA,MAC1C,iBAAA,EAAmB,QAAQ,iBAAA,IAAqB;AAAA,KAClD;AAAA,IACA;AAAA,GACF;AACF","file":"index.cjs","sourcesContent":["// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","/**\n * `@productcraft/auth-passport` — passport-jwt adapter for Auth.\n *\n * Install alongside `@productcraft/auth` + `passport-jwt`:\n *\n * ```bash\n * npm install @productcraft/auth @productcraft/auth-passport passport-jwt\n * ```\n *\n * Recommended one-call form:\n *\n * ```ts\n * import passportJwt from \"passport-jwt\";\n * import passport from \"passport\";\n * import { Auth } from \"@productcraft/auth\";\n * import { createAuthJwtStrategy } from \"@productcraft/auth-passport\";\n *\n * const auth = new Auth({ auth: { type: \"apiKey\", key: process.env.PCFT_KEY! } });\n * const scope = auth.consumer(\"my-app-slug\");\n *\n * passport.use(createAuthJwtStrategy(scope, (claims, done) => {\n * // claims is the verified Auth claims object (sub, role, permissions, ...)\n * return done(null, claims);\n * }));\n * ```\n *\n * The helper wires `secretOrKeyProvider` + `issuer` (per-app URL) +\n * `audience` (app slug) + algorithms automatically from the scope.\n *\n * If you need the underlying primitives — to compose with your own\n * options or pass a custom `jwtFromRequest` — use the lower-level\n * `createPassportSecretOrKeyProvider` directly:\n *\n * ```ts\n * new passportJwt.Strategy(\n * {\n * jwtFromRequest: passportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),\n * secretOrKeyProvider: createPassportSecretOrKeyProvider(scope),\n * issuer: scope.acceptedIssuers as string[],\n * audience: scope.expectedAudience,\n * algorithms: [\"RS256\", \"ES256\"],\n * },\n * (payload, done) => done(null, payload),\n * );\n * ```\n */\n\nimport { KeyObject } from \"node:crypto\";\nimport { createRequire } from \"node:module\";\nimport { decodeProtectedHeader, type JWTHeaderParameters } from \"jose\";\n\nimport type { ConsumerScope } from \"@productcraft/auth\";\n\n/**\n * passport-jwt's `secretOrKeyProvider` callback signature. We don't\n * depend on passport-jwt's types directly (to keep it a soft dep),\n * so this is the same shape as `SecretOrKeyProvider` in their typings.\n */\ntype PassportSecretOrKeyProvider = (\n request: unknown,\n rawJwtToken: string,\n done: (err: unknown, secretOrKey?: string | Buffer | KeyObject) => void,\n) => void;\n\n/**\n * Returns a passport-jwt `secretOrKeyProvider` bound to an Auth\n * `ConsumerScope`. Decodes the protected header, looks up the matching\n * key via the scope's JWKS cache, and converts the resulting jose\n * `CryptoKey` into a Node `KeyObject` that `jsonwebtoken` (the library\n * passport-jwt delegates to) accepts.\n */\nexport function createPassportSecretOrKeyProvider(\n scope: ConsumerScope,\n): PassportSecretOrKeyProvider {\n return (_request, rawJwt, done) => {\n let header;\n try {\n header = decodeProtectedHeader(rawJwt);\n } catch (err) {\n done(err);\n return;\n }\n\n scope.jwks.getKey(header as JWTHeaderParameters).then(\n (cryptoKey) => {\n try {\n // `jsonwebtoken` (passport-jwt's verifier) doesn't accept\n // Web Crypto `CryptoKey`, but it does accept Node's\n // `KeyObject`. `KeyObject.from(cryptoKey)` was added in\n // Node 16.6 and is the right adapter.\n const keyObject = KeyObject.from(cryptoKey);\n done(null, keyObject);\n } catch (err) {\n done(err);\n }\n },\n (err) => done(err),\n );\n };\n}\n\n/**\n * Shape of the verified-claims callback passport delegates to once a\n * token passes signature + issuer + audience + expiry checks. Mirrors\n * `passport-jwt`'s own `VerifyCallback` / `VerifyCallbackWithRequest`.\n */\nexport type AuthVerifyCallback = (\n payload: Record<string, unknown>,\n done: (err: unknown, user?: unknown, info?: unknown) => void,\n) => void;\n\n/**\n * Extra options for `createAuthJwtStrategy`. Defaults are the\n * Auth-recommended values; override here if you need a different\n * token source (cookie, custom header, ...), a stricter algorithm\n * allow-list, or want to skip the legacy-issuer acceptance window.\n */\nexport interface CreateAuthJwtStrategyOptions {\n /**\n * Where to read the bearer from. Defaults to\n * `ExtractJwt.fromAuthHeaderAsBearerToken()`. Pass any\n * passport-jwt extractor when you need a different source.\n */\n jwtFromRequest?: (req: unknown) => string | null;\n\n /**\n * JWS algorithms accepted by the underlying verifier. Defaults to\n * the algorithms Auth mints today (`['RS256']`); set explicitly\n * if your app is on a different signing alg or you also accept\n * customer-minted tokens with a different alg.\n */\n algorithms?: string[];\n\n /**\n * Pin only the per-app issuer URL (skip the legacy `'heimdall'`\n * literal). Defaults to `false` — verifying both keeps in-flight\n * tokens minted before the per-app-issuer migration valid. Set to\n * `true` once you're confident all old tokens have expired.\n */\n strictIssuer?: boolean;\n\n /** Whether the request object should be passed to the verify callback. Defaults to `false`. */\n passReqToCallback?: boolean;\n}\n\n/**\n * Constructor signature for `passport-jwt`'s `Strategy`. We don't take\n * a direct dep on passport-jwt to keep it a peer/soft dep — at runtime\n * the caller imports passportJwt and the helper does\n * `new passportJwt.Strategy(...)` via the constructor reference.\n */\nexport interface PassportJwtStrategyCtor {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n new (options: Record<string, unknown>, verify: AuthVerifyCallback): any;\n}\n\n/**\n * Lazy passport-jwt loader. We resolve `passport-jwt` from the\n * caller's dep graph at first use. Throws a clear error if it's\n * missing so the user doesn't see a cryptic `Cannot find module`\n * deep in the strategy constructor.\n *\n * Uses `createRequire` rather than a bare `require()`: tsup compiles a\n * bare `require` in the ESM bundle to a stub that throws \"Dynamic\n * require is not supported\", which made the ESM build unusable\n * (misreported as passport-jwt missing) while CJS worked fine.\n */\nfunction loadPassportJwt(): {\n Strategy: PassportJwtStrategyCtor;\n ExtractJwt: { fromAuthHeaderAsBearerToken: () => (req: unknown) => string | null };\n} {\n try {\n // dynamic require so passport-jwt stays a peer dep\n const requireFromHere = createRequire(import.meta.url);\n const mod = requireFromHere(\"passport-jwt\");\n return {\n Strategy: mod.Strategy ?? mod.default?.Strategy,\n ExtractJwt: mod.ExtractJwt ?? mod.default?.ExtractJwt,\n };\n } catch {\n throw new Error(\n \"@productcraft/auth-passport: `passport-jwt` is not installed. Run `npm install passport-jwt @types/passport-jwt`.\",\n );\n }\n}\n\n/**\n * Build a fully-configured `passport-jwt` strategy from an Auth\n * `ConsumerScope`. Wires:\n *\n * - `jwtFromRequest` → `ExtractJwt.fromAuthHeaderAsBearerToken()` (override via opts)\n * - `secretOrKeyProvider` → JWKS-backed key resolution via `scope.jwks`\n * - `issuer` → both `scope.expectedIssuer` AND the legacy `'heimdall'` literal (or only the per-app URL if `strictIssuer: true`)\n * - `audience` → `scope.expectedAudience` (the app slug)\n * - `algorithms` → `['RS256']` (override via opts)\n *\n * The verify callback you pass receives the parsed claims after\n * passport-jwt has finished its checks.\n */\nexport function createAuthJwtStrategy(\n scope: ConsumerScope,\n verify: AuthVerifyCallback,\n options: CreateAuthJwtStrategyOptions = {},\n) {\n const passportJwt = loadPassportJwt();\n const issuer = options.strictIssuer\n ? scope.expectedIssuer\n : (scope.acceptedIssuers as string[]);\n\n return new passportJwt.Strategy(\n {\n jwtFromRequest:\n options.jwtFromRequest ?? passportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),\n secretOrKeyProvider: createPassportSecretOrKeyProvider(scope),\n issuer,\n audience: scope.expectedAudience,\n algorithms: options.algorithms ?? [\"RS256\"],\n passReqToCallback: options.passReqToCallback ?? false,\n },\n verify,\n );\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { KeyObject } from 'crypto';
|
|
2
|
+
import { createRequire } from 'module';
|
|
2
3
|
import { decodeProtectedHeader } from 'jose';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
6
|
-
}) : x)(function(x) {
|
|
7
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
8
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
9
|
-
});
|
|
5
|
+
// src/index.ts
|
|
10
6
|
function createPassportSecretOrKeyProvider(scope) {
|
|
11
7
|
return (_request, rawJwt, done) => {
|
|
12
8
|
let header;
|
|
@@ -31,7 +27,8 @@ function createPassportSecretOrKeyProvider(scope) {
|
|
|
31
27
|
}
|
|
32
28
|
function loadPassportJwt() {
|
|
33
29
|
try {
|
|
34
|
-
const
|
|
30
|
+
const requireFromHere = createRequire(import.meta.url);
|
|
31
|
+
const mod = requireFromHere("passport-jwt");
|
|
35
32
|
return {
|
|
36
33
|
Strategy: mod.Strategy ?? mod.default?.Strategy,
|
|
37
34
|
ExtractJwt: mod.ExtractJwt ?? mod.default?.ExtractJwt
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAuEO,SAAS,kCACd,KAAA,EAC6B;AAC7B,EAAA,OAAO,CAAC,QAAA,EAAU,MAAA,EAAQ,IAAA,KAAS;AACjC,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAA,GAAS,sBAAsB,MAAM,CAAA;AAAA,IACvC,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,GAAG,CAAA;AACR,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,CAAM,IAAA,CAAK,MAAA,CAAO,MAA6B,CAAA,CAAE,IAAA;AAAA,MAC/C,CAAC,SAAA,KAAc;AACb,QAAA,IAAI;AAKF,UAAA,MAAM,SAAA,GAAY,SAAA,CAAU,IAAA,CAAK,SAAS,CAAA;AAC1C,UAAA,IAAA,CAAK,MAAM,SAAS,CAAA;AAAA,QACtB,SAAS,GAAA,EAAK;AACZ,UAAA,IAAA,CAAK,GAAG,CAAA;AAAA,QACV;AAAA,MACF,CAAA;AAAA,MACA,CAAC,GAAA,KAAQ,IAAA,CAAK,GAAG;AAAA,KACnB;AAAA,EACF,CAAA;AACF;AAoEA,SAAS,eAAA,GAGP;AACA,EAAA,IAAI;AAEF,IAAA,MAAM,eAAA,GAAkB,aAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AACrD,IAAA,MAAM,GAAA,GAAM,gBAAgB,cAAc,CAAA;AAC1C,IAAA,OAAO;AAAA,MACL,QAAA,EAAU,GAAA,CAAI,QAAA,IAAY,GAAA,CAAI,OAAA,EAAS,QAAA;AAAA,MACvC,UAAA,EAAY,GAAA,CAAI,UAAA,IAAc,GAAA,CAAI,OAAA,EAAS;AAAA,KAC7C;AAAA,EACF,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AACF;AAeO,SAAS,qBAAA,CACd,KAAA,EACA,MAAA,EACA,OAAA,GAAwC,EAAC,EACzC;AACA,EAAA,MAAM,cAAc,eAAA,EAAgB;AACpC,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,YAAA,GACnB,KAAA,CAAM,iBACL,KAAA,CAAM,eAAA;AAEX,EAAA,OAAO,IAAI,WAAA,CAAY,QAAA;AAAA,IACrB;AAAA,MACE,cAAA,EACE,OAAA,CAAQ,cAAA,IAAkB,WAAA,CAAY,WAAW,2BAAA,EAA4B;AAAA,MAC/E,mBAAA,EAAqB,kCAAkC,KAAK,CAAA;AAAA,MAC5D,MAAA;AAAA,MACA,UAAU,KAAA,CAAM,gBAAA;AAAA,MAChB,UAAA,EAAY,OAAA,CAAQ,UAAA,IAAc,CAAC,OAAO,CAAA;AAAA,MAC1C,iBAAA,EAAmB,QAAQ,iBAAA,IAAqB;AAAA,KAClD;AAAA,IACA;AAAA,GACF;AACF","file":"index.js","sourcesContent":["/**\n * `@productcraft/auth-passport` — passport-jwt adapter for Auth.\n *\n * Install alongside `@productcraft/auth` + `passport-jwt`:\n *\n * ```bash\n * npm install @productcraft/auth @productcraft/auth-passport passport-jwt\n * ```\n *\n * Recommended one-call form:\n *\n * ```ts\n * import passportJwt from \"passport-jwt\";\n * import passport from \"passport\";\n * import { Auth } from \"@productcraft/auth\";\n * import { createAuthJwtStrategy } from \"@productcraft/auth-passport\";\n *\n * const auth = new Auth({ auth: { type: \"apiKey\", key: process.env.PCFT_KEY! } });\n * const scope = auth.consumer(\"my-app-slug\");\n *\n * passport.use(createAuthJwtStrategy(scope, (claims, done) => {\n * // claims is the verified Auth claims object (sub, role, permissions, ...)\n * return done(null, claims);\n * }));\n * ```\n *\n * The helper wires `secretOrKeyProvider` + `issuer` (per-app URL) +\n * `audience` (app slug) + algorithms automatically from the scope.\n *\n * If you need the underlying primitives — to compose with your own\n * options or pass a custom `jwtFromRequest` — use the lower-level\n * `createPassportSecretOrKeyProvider` directly:\n *\n * ```ts\n * new passportJwt.Strategy(\n * {\n * jwtFromRequest: passportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),\n * secretOrKeyProvider: createPassportSecretOrKeyProvider(scope),\n * issuer: scope.acceptedIssuers as string[],\n * audience: scope.expectedAudience,\n * algorithms: [\"RS256\", \"ES256\"],\n * },\n * (payload, done) => done(null, payload),\n * );\n * ```\n */\n\nimport { KeyObject } from \"node:crypto\";\nimport { createRequire } from \"node:module\";\nimport { decodeProtectedHeader, type JWTHeaderParameters } from \"jose\";\n\nimport type { ConsumerScope } from \"@productcraft/auth\";\n\n/**\n * passport-jwt's `secretOrKeyProvider` callback signature. We don't\n * depend on passport-jwt's types directly (to keep it a soft dep),\n * so this is the same shape as `SecretOrKeyProvider` in their typings.\n */\ntype PassportSecretOrKeyProvider = (\n request: unknown,\n rawJwtToken: string,\n done: (err: unknown, secretOrKey?: string | Buffer | KeyObject) => void,\n) => void;\n\n/**\n * Returns a passport-jwt `secretOrKeyProvider` bound to an Auth\n * `ConsumerScope`. Decodes the protected header, looks up the matching\n * key via the scope's JWKS cache, and converts the resulting jose\n * `CryptoKey` into a Node `KeyObject` that `jsonwebtoken` (the library\n * passport-jwt delegates to) accepts.\n */\nexport function createPassportSecretOrKeyProvider(\n scope: ConsumerScope,\n): PassportSecretOrKeyProvider {\n return (_request, rawJwt, done) => {\n let header;\n try {\n header = decodeProtectedHeader(rawJwt);\n } catch (err) {\n done(err);\n return;\n }\n\n scope.jwks.getKey(header as JWTHeaderParameters).then(\n (cryptoKey) => {\n try {\n // `jsonwebtoken` (passport-jwt's verifier) doesn't accept\n // Web Crypto `CryptoKey`, but it does accept Node's\n // `KeyObject`. `KeyObject.from(cryptoKey)` was added in\n // Node 16.6 and is the right adapter.\n const keyObject = KeyObject.from(cryptoKey);\n done(null, keyObject);\n } catch (err) {\n done(err);\n }\n },\n (err) => done(err),\n );\n };\n}\n\n/**\n * Shape of the verified-claims callback passport delegates to once a\n * token passes signature + issuer + audience + expiry checks. Mirrors\n * `passport-jwt`'s own `VerifyCallback` / `VerifyCallbackWithRequest`.\n */\nexport type AuthVerifyCallback = (\n payload: Record<string, unknown>,\n done: (err: unknown, user?: unknown, info?: unknown) => void,\n) => void;\n\n/**\n * Extra options for `createAuthJwtStrategy`. Defaults are the\n * Auth-recommended values; override here if you need a different\n * token source (cookie, custom header, ...), a stricter algorithm\n * allow-list, or want to skip the legacy-issuer acceptance window.\n */\nexport interface CreateAuthJwtStrategyOptions {\n /**\n * Where to read the bearer from. Defaults to\n * `ExtractJwt.fromAuthHeaderAsBearerToken()`. Pass any\n * passport-jwt extractor when you need a different source.\n */\n jwtFromRequest?: (req: unknown) => string | null;\n\n /**\n * JWS algorithms accepted by the underlying verifier. Defaults to\n * the algorithms Auth mints today (`['RS256']`); set explicitly\n * if your app is on a different signing alg or you also accept\n * customer-minted tokens with a different alg.\n */\n algorithms?: string[];\n\n /**\n * Pin only the per-app issuer URL (skip the legacy `'heimdall'`\n * literal). Defaults to `false` — verifying both keeps in-flight\n * tokens minted before the per-app-issuer migration valid. Set to\n * `true` once you're confident all old tokens have expired.\n */\n strictIssuer?: boolean;\n\n /** Whether the request object should be passed to the verify callback. Defaults to `false`. */\n passReqToCallback?: boolean;\n}\n\n/**\n * Constructor signature for `passport-jwt`'s `Strategy`. We don't take\n * a direct dep on passport-jwt to keep it a peer/soft dep — at runtime\n * the caller imports passportJwt and the helper does\n * `new passportJwt.Strategy(...)` via the constructor reference.\n */\nexport interface PassportJwtStrategyCtor {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n new (options: Record<string, unknown>, verify: AuthVerifyCallback): any;\n}\n\n/**\n * Lazy passport-jwt loader. We resolve `passport-jwt` from the\n * caller's dep graph at first use. Throws a clear error if it's\n * missing so the user doesn't see a cryptic `Cannot find module`\n * deep in the strategy constructor.\n *\n * Uses `createRequire` rather than a bare `require()`: tsup compiles a\n * bare `require` in the ESM bundle to a stub that throws \"Dynamic\n * require is not supported\", which made the ESM build unusable\n * (misreported as passport-jwt missing) while CJS worked fine.\n */\nfunction loadPassportJwt(): {\n Strategy: PassportJwtStrategyCtor;\n ExtractJwt: { fromAuthHeaderAsBearerToken: () => (req: unknown) => string | null };\n} {\n try {\n // dynamic require so passport-jwt stays a peer dep\n const requireFromHere = createRequire(import.meta.url);\n const mod = requireFromHere(\"passport-jwt\");\n return {\n Strategy: mod.Strategy ?? mod.default?.Strategy,\n ExtractJwt: mod.ExtractJwt ?? mod.default?.ExtractJwt,\n };\n } catch {\n throw new Error(\n \"@productcraft/auth-passport: `passport-jwt` is not installed. Run `npm install passport-jwt @types/passport-jwt`.\",\n );\n }\n}\n\n/**\n * Build a fully-configured `passport-jwt` strategy from an Auth\n * `ConsumerScope`. Wires:\n *\n * - `jwtFromRequest` → `ExtractJwt.fromAuthHeaderAsBearerToken()` (override via opts)\n * - `secretOrKeyProvider` → JWKS-backed key resolution via `scope.jwks`\n * - `issuer` → both `scope.expectedIssuer` AND the legacy `'heimdall'` literal (or only the per-app URL if `strictIssuer: true`)\n * - `audience` → `scope.expectedAudience` (the app slug)\n * - `algorithms` → `['RS256']` (override via opts)\n *\n * The verify callback you pass receives the parsed claims after\n * passport-jwt has finished its checks.\n */\nexport function createAuthJwtStrategy(\n scope: ConsumerScope,\n verify: AuthVerifyCallback,\n options: CreateAuthJwtStrategyOptions = {},\n) {\n const passportJwt = loadPassportJwt();\n const issuer = options.strictIssuer\n ? scope.expectedIssuer\n : (scope.acceptedIssuers as string[]);\n\n return new passportJwt.Strategy(\n {\n jwtFromRequest:\n options.jwtFromRequest ?? passportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),\n secretOrKeyProvider: createPassportSecretOrKeyProvider(scope),\n issuer,\n audience: scope.expectedAudience,\n algorithms: options.algorithms ?? [\"RS256\"],\n passReqToCallback: options.passReqToCallback ?? false,\n },\n verify,\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@productcraft/auth-passport",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Passport-JWT adapter for ProductCraft Auth. Plug an Auth ConsumerScope into a `passport-jwt` Strategy so existing Passport setups can authenticate Auth-issued tokens.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -38,7 +38,8 @@
|
|
|
38
38
|
},
|
|
39
39
|
"homepage": "https://github.com/clauderanelagh/productcraft-node/tree/main/packages/auth-passport",
|
|
40
40
|
"publishConfig": {
|
|
41
|
-
"access": "public"
|
|
41
|
+
"access": "public",
|
|
42
|
+
"provenance": true
|
|
42
43
|
},
|
|
43
44
|
"dependencies": {
|
|
44
45
|
"jose": "^6.2.3",
|