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 +43 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +44 -0
- package/lib/index.js.map +1 -0
- package/package.json +1 -1
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
|
package/lib/index.js.map
ADDED
|
@@ -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"}
|