@productcraft/heimdall-passport 0.0.2

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/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # @productcraft/heimdall-passport
2
+
3
+ Passport-JWT adapter for [`@productcraft/heimdall`](../heimdall). Plug a Heimdall `ConsumerScope` into a `passport-jwt` Strategy so existing Passport setups can authenticate Heimdall-issued tokens.
4
+
5
+ ```bash
6
+ npm install @productcraft/heimdall @productcraft/heimdall-passport passport-jwt
7
+ ```
8
+
9
+ ## Usage
10
+
11
+ ```ts
12
+ import passportJwt from "passport-jwt";
13
+ import { Heimdall } from "@productcraft/heimdall";
14
+ import { createPassportSecretOrKeyProvider } from "@productcraft/heimdall-passport";
15
+
16
+ const heimdall = new Heimdall({
17
+ auth: { type: "apiKey", key: process.env.PCFT_KEY! },
18
+ });
19
+ const scope = heimdall.consumer("my-app-slug");
20
+
21
+ new passportJwt.Strategy(
22
+ {
23
+ jwtFromRequest: passportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),
24
+ secretOrKeyProvider: createPassportSecretOrKeyProvider(scope),
25
+ issuer: scope.expectedIssuer,
26
+ audience: "my-app", // optional
27
+ algorithms: ["ES256"],
28
+ },
29
+ (payload, done) => {
30
+ // payload is the verified Heimdall claims object (sub, role, permissions, ...)
31
+ return done(null, payload);
32
+ },
33
+ );
34
+ ```
35
+
36
+ The helper decodes the JWT header, asks the Heimdall `ConsumerScope` for the matching signing key via its cached JWKS, converts the resulting `CryptoKey` into a Node `KeyObject`, and hands it to passport-jwt.
37
+
38
+ ## How it relates to the main package
39
+
40
+ `@productcraft/heimdall` already ships a `scope.verifyToken(token)` one-liner. Use **this** package only when you have an existing Passport setup you'd rather keep. For Express middleware without Passport, the direct verify is simpler.
41
+
42
+ ## License
43
+
44
+ [MIT](../../LICENSE).
package/dist/index.cjs ADDED
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ var crypto = require('crypto');
4
+ var jose = require('jose');
5
+
6
+ // src/index.ts
7
+ function createPassportSecretOrKeyProvider(scope) {
8
+ return (_request, rawJwt, done) => {
9
+ let header;
10
+ try {
11
+ header = jose.decodeProtectedHeader(rawJwt);
12
+ } catch (err) {
13
+ done(err);
14
+ return;
15
+ }
16
+ scope.jwks.getKey(header).then(
17
+ (cryptoKey) => {
18
+ try {
19
+ const keyObject = crypto.KeyObject.from(cryptoKey);
20
+ done(null, keyObject);
21
+ } catch (err) {
22
+ done(err);
23
+ }
24
+ },
25
+ (err) => done(err)
26
+ );
27
+ };
28
+ }
29
+
30
+ exports.createPassportSecretOrKeyProvider = createPassportSecretOrKeyProvider;
31
+ //# sourceMappingURL=index.cjs.map
32
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":["decodeProtectedHeader","KeyObject"],"mappings":";;;;;;AAsDO,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","file":"index.cjs","sourcesContent":["/**\n * `@productcraft/heimdall-passport` — passport-jwt adapter for Heimdall.\n *\n * Install alongside `@productcraft/heimdall` + `passport-jwt`:\n *\n * ```bash\n * npm install @productcraft/heimdall @productcraft/heimdall-passport passport-jwt\n * ```\n *\n * Usage:\n *\n * ```ts\n * import passportJwt from \"passport-jwt\";\n * import { Heimdall } from \"@productcraft/heimdall\";\n * import { createPassportSecretOrKeyProvider } from \"@productcraft/heimdall-passport\";\n *\n * const heimdall = new Heimdall({ auth: { type: \"apiKey\", key: process.env.PCFT_KEY! } });\n * const scope = heimdall.consumer(\"my-app-slug\");\n *\n * new passportJwt.Strategy(\n * {\n * jwtFromRequest: passportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),\n * secretOrKeyProvider: createPassportSecretOrKeyProvider(scope),\n * issuer: scope.expectedIssuer,\n * algorithms: [\"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/heimdall\";\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 a Heimdall\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"]}
@@ -0,0 +1,50 @@
1
+ import { KeyObject } from 'node:crypto';
2
+ import { ConsumerScope } from '@productcraft/heimdall';
3
+
4
+ /**
5
+ * `@productcraft/heimdall-passport` — passport-jwt adapter for Heimdall.
6
+ *
7
+ * Install alongside `@productcraft/heimdall` + `passport-jwt`:
8
+ *
9
+ * ```bash
10
+ * npm install @productcraft/heimdall @productcraft/heimdall-passport passport-jwt
11
+ * ```
12
+ *
13
+ * Usage:
14
+ *
15
+ * ```ts
16
+ * import passportJwt from "passport-jwt";
17
+ * import { Heimdall } from "@productcraft/heimdall";
18
+ * import { createPassportSecretOrKeyProvider } from "@productcraft/heimdall-passport";
19
+ *
20
+ * const heimdall = new Heimdall({ auth: { type: "apiKey", key: process.env.PCFT_KEY! } });
21
+ * const scope = heimdall.consumer("my-app-slug");
22
+ *
23
+ * new passportJwt.Strategy(
24
+ * {
25
+ * jwtFromRequest: passportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),
26
+ * secretOrKeyProvider: createPassportSecretOrKeyProvider(scope),
27
+ * issuer: scope.expectedIssuer,
28
+ * algorithms: ["ES256"],
29
+ * },
30
+ * (payload, done) => done(null, payload),
31
+ * );
32
+ * ```
33
+ */
34
+
35
+ /**
36
+ * passport-jwt's `secretOrKeyProvider` callback signature. We don't
37
+ * depend on passport-jwt's types directly (to keep it a soft dep),
38
+ * so this is the same shape as `SecretOrKeyProvider` in their typings.
39
+ */
40
+ type PassportSecretOrKeyProvider = (request: unknown, rawJwtToken: string, done: (err: unknown, secretOrKey?: string | Buffer | KeyObject) => void) => void;
41
+ /**
42
+ * Returns a passport-jwt `secretOrKeyProvider` bound to a Heimdall
43
+ * `ConsumerScope`. Decodes the protected header, looks up the matching
44
+ * key via the scope's JWKS cache, and converts the resulting jose
45
+ * `CryptoKey` into a Node `KeyObject` that `jsonwebtoken` (the library
46
+ * passport-jwt delegates to) accepts.
47
+ */
48
+ declare function createPassportSecretOrKeyProvider(scope: ConsumerScope): PassportSecretOrKeyProvider;
49
+
50
+ export { createPassportSecretOrKeyProvider };
@@ -0,0 +1,50 @@
1
+ import { KeyObject } from 'node:crypto';
2
+ import { ConsumerScope } from '@productcraft/heimdall';
3
+
4
+ /**
5
+ * `@productcraft/heimdall-passport` — passport-jwt adapter for Heimdall.
6
+ *
7
+ * Install alongside `@productcraft/heimdall` + `passport-jwt`:
8
+ *
9
+ * ```bash
10
+ * npm install @productcraft/heimdall @productcraft/heimdall-passport passport-jwt
11
+ * ```
12
+ *
13
+ * Usage:
14
+ *
15
+ * ```ts
16
+ * import passportJwt from "passport-jwt";
17
+ * import { Heimdall } from "@productcraft/heimdall";
18
+ * import { createPassportSecretOrKeyProvider } from "@productcraft/heimdall-passport";
19
+ *
20
+ * const heimdall = new Heimdall({ auth: { type: "apiKey", key: process.env.PCFT_KEY! } });
21
+ * const scope = heimdall.consumer("my-app-slug");
22
+ *
23
+ * new passportJwt.Strategy(
24
+ * {
25
+ * jwtFromRequest: passportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),
26
+ * secretOrKeyProvider: createPassportSecretOrKeyProvider(scope),
27
+ * issuer: scope.expectedIssuer,
28
+ * algorithms: ["ES256"],
29
+ * },
30
+ * (payload, done) => done(null, payload),
31
+ * );
32
+ * ```
33
+ */
34
+
35
+ /**
36
+ * passport-jwt's `secretOrKeyProvider` callback signature. We don't
37
+ * depend on passport-jwt's types directly (to keep it a soft dep),
38
+ * so this is the same shape as `SecretOrKeyProvider` in their typings.
39
+ */
40
+ type PassportSecretOrKeyProvider = (request: unknown, rawJwtToken: string, done: (err: unknown, secretOrKey?: string | Buffer | KeyObject) => void) => void;
41
+ /**
42
+ * Returns a passport-jwt `secretOrKeyProvider` bound to a Heimdall
43
+ * `ConsumerScope`. Decodes the protected header, looks up the matching
44
+ * key via the scope's JWKS cache, and converts the resulting jose
45
+ * `CryptoKey` into a Node `KeyObject` that `jsonwebtoken` (the library
46
+ * passport-jwt delegates to) accepts.
47
+ */
48
+ declare function createPassportSecretOrKeyProvider(scope: ConsumerScope): PassportSecretOrKeyProvider;
49
+
50
+ export { createPassportSecretOrKeyProvider };
package/dist/index.js ADDED
@@ -0,0 +1,30 @@
1
+ import { KeyObject } from 'crypto';
2
+ import { decodeProtectedHeader } from 'jose';
3
+
4
+ // src/index.ts
5
+ function createPassportSecretOrKeyProvider(scope) {
6
+ return (_request, rawJwt, done) => {
7
+ let header;
8
+ try {
9
+ header = decodeProtectedHeader(rawJwt);
10
+ } catch (err) {
11
+ done(err);
12
+ return;
13
+ }
14
+ scope.jwks.getKey(header).then(
15
+ (cryptoKey) => {
16
+ try {
17
+ const keyObject = KeyObject.from(cryptoKey);
18
+ done(null, keyObject);
19
+ } catch (err) {
20
+ done(err);
21
+ }
22
+ },
23
+ (err) => done(err)
24
+ );
25
+ };
26
+ }
27
+
28
+ export { createPassportSecretOrKeyProvider };
29
+ //# sourceMappingURL=index.js.map
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;;AAsDO,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","file":"index.js","sourcesContent":["/**\n * `@productcraft/heimdall-passport` — passport-jwt adapter for Heimdall.\n *\n * Install alongside `@productcraft/heimdall` + `passport-jwt`:\n *\n * ```bash\n * npm install @productcraft/heimdall @productcraft/heimdall-passport passport-jwt\n * ```\n *\n * Usage:\n *\n * ```ts\n * import passportJwt from \"passport-jwt\";\n * import { Heimdall } from \"@productcraft/heimdall\";\n * import { createPassportSecretOrKeyProvider } from \"@productcraft/heimdall-passport\";\n *\n * const heimdall = new Heimdall({ auth: { type: \"apiKey\", key: process.env.PCFT_KEY! } });\n * const scope = heimdall.consumer(\"my-app-slug\");\n *\n * new passportJwt.Strategy(\n * {\n * jwtFromRequest: passportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),\n * secretOrKeyProvider: createPassportSecretOrKeyProvider(scope),\n * issuer: scope.expectedIssuer,\n * algorithms: [\"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/heimdall\";\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 a Heimdall\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"]}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@productcraft/heimdall-passport",
3
+ "version": "0.0.2",
4
+ "description": "Passport-JWT adapter for ProductCraft Heimdall. Plug a Heimdall ConsumerScope into a `passport-jwt` Strategy so existing Passport setups can authenticate Heimdall-issued tokens.",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist/**",
18
+ "README.md",
19
+ "LICENSE"
20
+ ],
21
+ "engines": {
22
+ "node": ">=18"
23
+ },
24
+ "scripts": {
25
+ "build": "tsup",
26
+ "test": "vitest run"
27
+ },
28
+ "keywords": [
29
+ "productcraft",
30
+ "sdk",
31
+ "heimdall",
32
+ "passport",
33
+ "passport-jwt",
34
+ "auth",
35
+ "jwt"
36
+ ],
37
+ "author": "ProductCraft",
38
+ "license": "MIT",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/clauderanelagh/productcraft-node.git",
42
+ "directory": "packages/heimdall-passport"
43
+ },
44
+ "homepage": "https://github.com/clauderanelagh/productcraft-node/tree/main/packages/heimdall-passport",
45
+ "publishConfig": {
46
+ "access": "public",
47
+ "provenance": true
48
+ },
49
+ "dependencies": {
50
+ "@productcraft/heimdall": "workspace:^",
51
+ "jose": "^6.2.3"
52
+ },
53
+ "peerDependencies": {
54
+ "passport-jwt": "^4.0.0"
55
+ }
56
+ }