fastify-portcullis 1.0.0 → 1.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/lib/index.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ import '@fastify/jwt';
2
+ import type { FastifyPluginAsync } from 'fastify';
3
+ /** Shape of the authenticated principal attached to every verified request. */
4
+ export interface PortcullisUser {
5
+ email: string;
6
+ }
7
+ /**
8
+ * Options accepted by the plugin when registered with `fastify.register()`.
9
+ */
10
+ export interface PortcullisPluginOptions {
11
+ /**
12
+ * JWT verification secret.
13
+ *
14
+ * - **string** — symmetric HS256 shared secret (suitable for test
15
+ * environments and services that share a secret with Portcullis)
16
+ * - **{ private, public }** — asymmetric ES256 PEM key pair as issued by
17
+ * Portcullis in production; services only need the `public` key to
18
+ * verify tokens but the full pair is accepted so a signer can be
19
+ * co-located for testing
20
+ */
21
+ secret: string | {
22
+ private: string | Buffer;
23
+ public: string | Buffer;
24
+ };
25
+ /**
26
+ * URL paths that bypass JWT enforcement entirely.
27
+ * Defaults to `['/health']`.
28
+ */
29
+ exempt?: string[];
30
+ /**
31
+ * When set, the JWT `iss` (issuer) claim must equal this value.
32
+ * Tokens with a missing or non-matching issuer are rejected with 400.
33
+ */
34
+ issuer?: string;
35
+ }
36
+ declare module '@fastify/jwt' {
37
+ interface FastifyJWT {
38
+ user: PortcullisUser;
39
+ }
40
+ }
41
+ declare const _default: FastifyPluginAsync<PortcullisPluginOptions>;
42
+ export default _default;
43
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,cAAc,CAAA;AACrB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAMjD,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC3B,KAAK,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACpC;;;;;;;;;OASG;IACH,MAAM,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAA;IAEtE;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IAEjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CAClB;AAQD,OAAO,QAAQ,cAAc,CAAC;IAC1B,UAAU,UAAU;QAChB,IAAI,EAAE,cAAc,CAAA;KACvB;CACJ;;AA6CD,wBAGE"}
package/lib/index.js ADDED
@@ -0,0 +1,44 @@
1
+ import fp from 'fastify-plugin';
2
+ import fastifyJwt from '@fastify/jwt';
3
+ import '@fastify/jwt'; // side-effect: ensures @fastify/jwt's FastifyRequest augmentation
4
+ // ---------------------------------------------------------------------------
5
+ // Plugin implementation
6
+ // ---------------------------------------------------------------------------
7
+ const plugin = async (fastify, opts) => {
8
+ const exempt = new Set(opts.exempt ?? ['/health']);
9
+ await fastify.register(fastifyJwt, {
10
+ // Cast: our public API is a strict subset of @fastify/jwt's Secret union
11
+ secret: opts.secret,
12
+ ...(opts.issuer
13
+ ? { verify: { allowedIss: [opts.issuer] } }
14
+ : {}),
15
+ });
16
+ fastify.addHook('onRequest', async (request, reply) => {
17
+ if (exempt.has(request.url))
18
+ return;
19
+ if (!request.headers.authorization) {
20
+ return reply.status(401).send({ error: 'Unauthorized' });
21
+ }
22
+ try {
23
+ await request.jwtVerify();
24
+ }
25
+ catch {
26
+ return reply.status(400).send({ error: 'Invalid token' });
27
+ }
28
+ // @fastify/jwt's allowedIss only rejects tokens where iss is present
29
+ // but wrong — it silently passes tokens that omit iss entirely. When
30
+ // the caller has configured issuer validation we enforce presence too.
31
+ const payload = request.user;
32
+ if (opts.issuer && payload.iss !== opts.issuer) {
33
+ return reply.status(400).send({ error: 'Invalid token' });
34
+ }
35
+ if (!payload.email) {
36
+ return reply.status(400).send({ error: 'Token must contain a valid email claim' });
37
+ }
38
+ });
39
+ };
40
+ export default fp(plugin, {
41
+ fastify: '>=5.0.0',
42
+ name: 'fastify-portcullis',
43
+ });
44
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAC/B,OAAO,UAAU,MAAM,cAAc,CAAA;AACrC,OAAO,cAAc,CAAA,CAAG,kEAAkE;AAqD1F,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E,MAAM,MAAM,GAAgD,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;IAChF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,CAAA;IAElD,MAAM,OAAO,CAAC,QAAQ,CAAC,UAAU,EAAE;QAC/B,yEAAyE;QACzE,MAAM,EAAE,IAAI,CAAC,MAAoD;QACjE,GAAG,CAAC,IAAI,CAAC,MAAM;YACX,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE;YAC3C,CAAC,CAAC,EAAE,CAAC;KACZ,CAAC,CAAA;IAEF,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAClD,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC;YAAE,OAAM;QAEnC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YACjC,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAA;QAC5D,CAAC;QAED,IAAI,CAAC;YACD,MAAM,OAAO,CAAC,SAAS,EAAE,CAAA;QAC7B,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAA;QAC7D,CAAC;QAED,qEAAqE;QACrE,qEAAqE;QACrE,uEAAuE;QACvE,MAAM,OAAO,GAAG,OAAO,CAAC,IAA0C,CAAA;QAElE,IAAI,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;YAC7C,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAA;QAC7D,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACjB,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,wCAAwC,EAAE,CAAC,CAAA;QACtF,CAAC;IACL,CAAC,CAAC,CAAA;AACN,CAAC,CAAA;AAED,eAAe,EAAE,CAAC,MAAM,EAAE;IACtB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,oBAAoB;CAC7B,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastify-portcullis",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Fastify plugin: JWT authentication for services behind a Portcullis proxy",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",