cloudflare-access 1.0.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.
Files changed (70) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +452 -0
  3. package/dist/adapters/effect/index.d.mts +167 -0
  4. package/dist/adapters/effect/index.d.ts +167 -0
  5. package/dist/adapters/effect/index.js +221 -0
  6. package/dist/adapters/effect/index.js.map +1 -0
  7. package/dist/adapters/effect/index.mjs +221 -0
  8. package/dist/adapters/effect/index.mjs.map +1 -0
  9. package/dist/adapters/express/index.d.mts +74 -0
  10. package/dist/adapters/express/index.d.ts +74 -0
  11. package/dist/adapters/express/index.js +129 -0
  12. package/dist/adapters/express/index.js.map +1 -0
  13. package/dist/adapters/express/index.mjs +129 -0
  14. package/dist/adapters/express/index.mjs.map +1 -0
  15. package/dist/adapters/fastify/index.d.mts +111 -0
  16. package/dist/adapters/fastify/index.d.ts +111 -0
  17. package/dist/adapters/fastify/index.js +140 -0
  18. package/dist/adapters/fastify/index.js.map +1 -0
  19. package/dist/adapters/fastify/index.mjs +140 -0
  20. package/dist/adapters/fastify/index.mjs.map +1 -0
  21. package/dist/adapters/hono/index.d.mts +19 -0
  22. package/dist/adapters/hono/index.d.ts +19 -0
  23. package/dist/adapters/hono/index.js +45 -0
  24. package/dist/adapters/hono/index.js.map +1 -0
  25. package/dist/adapters/hono/index.mjs +45 -0
  26. package/dist/adapters/hono/index.mjs.map +1 -0
  27. package/dist/adapters/nestjs/index.d.mts +123 -0
  28. package/dist/adapters/nestjs/index.d.ts +123 -0
  29. package/dist/adapters/nestjs/index.js +117 -0
  30. package/dist/adapters/nestjs/index.js.map +1 -0
  31. package/dist/adapters/nestjs/index.mjs +117 -0
  32. package/dist/adapters/nestjs/index.mjs.map +1 -0
  33. package/dist/chunk-DM2KGIQX.mjs +320 -0
  34. package/dist/chunk-DM2KGIQX.mjs.map +1 -0
  35. package/dist/chunk-LQWCGHLJ.mjs +108 -0
  36. package/dist/chunk-LQWCGHLJ.mjs.map +1 -0
  37. package/dist/chunk-PMFPT3SI.js +108 -0
  38. package/dist/chunk-PMFPT3SI.js.map +1 -0
  39. package/dist/chunk-WUJPWM4T.js +320 -0
  40. package/dist/chunk-WUJPWM4T.js.map +1 -0
  41. package/dist/config-D4O7DXNT.d.mts +12 -0
  42. package/dist/config-ottUdc-K.d.ts +12 -0
  43. package/dist/core/index.d.mts +24 -0
  44. package/dist/core/index.d.ts +24 -0
  45. package/dist/core/index.js +41 -0
  46. package/dist/core/index.js.map +1 -0
  47. package/dist/core/index.mjs +41 -0
  48. package/dist/core/index.mjs.map +1 -0
  49. package/dist/index.d.mts +6 -0
  50. package/dist/index.d.ts +6 -0
  51. package/dist/index.js +41 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/index.mjs +41 -0
  54. package/dist/index.mjs.map +1 -0
  55. package/dist/jwks-ChdyyS_L.d.mts +173 -0
  56. package/dist/jwks-ChdyyS_L.d.ts +173 -0
  57. package/dist/middleware-BDl6jUCu.d.mts +83 -0
  58. package/dist/middleware-CgFsjM20.d.ts +83 -0
  59. package/examples/basic.ts +52 -0
  60. package/examples/cloudflare-workers.ts +84 -0
  61. package/examples/custom-handlers.ts +85 -0
  62. package/examples/effect/http-server.ts +205 -0
  63. package/examples/email-allowlist.ts +50 -0
  64. package/examples/express/basic.ts +26 -0
  65. package/examples/fastify/basic.ts +24 -0
  66. package/examples/hono/basic.ts +26 -0
  67. package/examples/hono-router.ts +74 -0
  68. package/examples/nestjs/basic.ts +39 -0
  69. package/examples/skip-dev-mode.ts +89 -0
  70. package/package.json +178 -0
@@ -0,0 +1,123 @@
1
+ import { C as CloudflareAccessConfig, e as CloudflareAccessMiddlewareEnv, g as CloudflareAccessUser } from '../../jwks-ChdyyS_L.mjs';
2
+ export { A as AccessDeniedError, a as AuthRequiredError, c as CloudflareAccessError, d as CloudflareAccessErrorCode, f as CloudflareAccessPayload, h as ConfigurationError, I as InvalidTokenError, _ as __clearJwksCache, i as isAccessDeniedError, j as isAuthRequiredError, k as isCloudflareAccessError, l as isConfigurationError, m as isInvalidTokenError, t as toAuthError } from '../../jwks-ChdyyS_L.mjs';
3
+ import * as _nestjs_common from '@nestjs/common';
4
+ import { CanActivate, ExecutionContext, ModuleMetadata, Type } from '@nestjs/common';
5
+ import 'jose';
6
+
7
+ /**
8
+ * Options for Cloudflare Access Guard
9
+ */
10
+ interface CloudflareAccessGuardOptions {
11
+ /** Cloudflare Access configuration */
12
+ accessConfig: CloudflareAccessConfig;
13
+ /** Optional email allowlist. Access policy should still be configured at Cloudflare. */
14
+ allowedEmails?: string[];
15
+ /** Whether to skip JWT validation outside production */
16
+ skipInDev?: boolean;
17
+ /** Environment indicator */
18
+ environment?: string;
19
+ }
20
+ /**
21
+ * Get Cloudflare Access configuration from environment variables
22
+ */
23
+ declare function getCloudflareAccessConfigFromEnv(env: CloudflareAccessMiddlewareEnv): CloudflareAccessConfig;
24
+
25
+ declare module "express" {
26
+ interface Request {
27
+ user?: CloudflareAccessUser;
28
+ }
29
+ }
30
+ /**
31
+ * NestJS Guard for Cloudflare Access authentication.
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * import { Module } from '@nestjs/common';
36
+ * import { APP_GUARD } from '@nestjs/core';
37
+ * import { CloudflareAccessGuard } from 'cloudflare-access/adapters/nestjs';
38
+ *
39
+ * @Module({
40
+ * providers: [
41
+ * {
42
+ * provide: APP_GUARD,
43
+ * useFactory: () => new CloudflareAccessGuard({
44
+ * accessConfig: {
45
+ * teamDomain: 'https://yourteam.cloudflareaccess.com',
46
+ * audTag: 'your-audience-tag',
47
+ * },
48
+ * }),
49
+ * },
50
+ * ],
51
+ * })
52
+ * export class AppModule {}
53
+ * ```
54
+ */
55
+ declare class CloudflareAccessGuard implements CanActivate {
56
+ private readonly options;
57
+ private readonly allowedEmails;
58
+ constructor(options: CloudflareAccessGuardOptions);
59
+ canActivate(context: ExecutionContext): Promise<boolean>;
60
+ private isPublicRoute;
61
+ }
62
+
63
+ /**
64
+ * Metadata key for public routes
65
+ */
66
+ declare const IS_PUBLIC_KEY = "cfAccessPublic";
67
+
68
+ /**
69
+ * Decorator to mark a route as public (skip auth)
70
+ */
71
+ declare const Public: () => _nestjs_common.CustomDecorator<string>;
72
+ /**
73
+ * Decorator to apply Cloudflare Access authentication to a route or controller.
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * import { Controller, Get } from '@nestjs/common';
78
+ * import { CloudflareAccess, Public } from 'cloudflare-access/adapters/nestjs';
79
+ *
80
+ * @Controller('api')
81
+ * @CloudflareAccess({
82
+ * accessConfig: {
83
+ * teamDomain: 'https://yourteam.cloudflareaccess.com',
84
+ * audTag: 'your-audience-tag',
85
+ * },
86
+ * })
87
+ * export class ApiController {
88
+ * @Get('protected')
89
+ * getProtected(@Req() req: Request) {
90
+ * return { email: req.user?.email };
91
+ * }
92
+ *
93
+ * @Public()
94
+ * @Get('public')
95
+ * getPublic() {
96
+ * return { message: 'This is public' };
97
+ * }
98
+ * }
99
+ * ```
100
+ */
101
+ declare function CloudflareAccess(options: CloudflareAccessGuardOptions): <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
102
+ /**
103
+ * Interface for async options for Cloudflare Access module
104
+ */
105
+ interface CloudflareAccessModuleAsyncOptions extends Pick<ModuleMetadata, "imports"> {
106
+ useExisting?: Type<{
107
+ createCloudflareAccessOptions(): Promise<CloudflareAccessGuardOptions> | CloudflareAccessGuardOptions;
108
+ }>;
109
+ useClass?: Type<{
110
+ createCloudflareAccessOptions(): Promise<CloudflareAccessGuardOptions> | CloudflareAccessGuardOptions;
111
+ }>;
112
+ useFactory?: (...args: any[]) => Promise<CloudflareAccessGuardOptions> | CloudflareAccessGuardOptions;
113
+ inject?: any[];
114
+ }
115
+
116
+ declare module "express" {
117
+ interface Request {
118
+ /** Authenticated user from Cloudflare Access */
119
+ user?: CloudflareAccessUser;
120
+ }
121
+ }
122
+
123
+ export { CloudflareAccess, CloudflareAccessConfig, CloudflareAccessGuard, type CloudflareAccessGuardOptions, CloudflareAccessMiddlewareEnv, type CloudflareAccessModuleAsyncOptions, CloudflareAccessUser, IS_PUBLIC_KEY, Public, getCloudflareAccessConfigFromEnv };
@@ -0,0 +1,123 @@
1
+ import { C as CloudflareAccessConfig, e as CloudflareAccessMiddlewareEnv, g as CloudflareAccessUser } from '../../jwks-ChdyyS_L.js';
2
+ export { A as AccessDeniedError, a as AuthRequiredError, c as CloudflareAccessError, d as CloudflareAccessErrorCode, f as CloudflareAccessPayload, h as ConfigurationError, I as InvalidTokenError, _ as __clearJwksCache, i as isAccessDeniedError, j as isAuthRequiredError, k as isCloudflareAccessError, l as isConfigurationError, m as isInvalidTokenError, t as toAuthError } from '../../jwks-ChdyyS_L.js';
3
+ import * as _nestjs_common from '@nestjs/common';
4
+ import { CanActivate, ExecutionContext, ModuleMetadata, Type } from '@nestjs/common';
5
+ import 'jose';
6
+
7
+ /**
8
+ * Options for Cloudflare Access Guard
9
+ */
10
+ interface CloudflareAccessGuardOptions {
11
+ /** Cloudflare Access configuration */
12
+ accessConfig: CloudflareAccessConfig;
13
+ /** Optional email allowlist. Access policy should still be configured at Cloudflare. */
14
+ allowedEmails?: string[];
15
+ /** Whether to skip JWT validation outside production */
16
+ skipInDev?: boolean;
17
+ /** Environment indicator */
18
+ environment?: string;
19
+ }
20
+ /**
21
+ * Get Cloudflare Access configuration from environment variables
22
+ */
23
+ declare function getCloudflareAccessConfigFromEnv(env: CloudflareAccessMiddlewareEnv): CloudflareAccessConfig;
24
+
25
+ declare module "express" {
26
+ interface Request {
27
+ user?: CloudflareAccessUser;
28
+ }
29
+ }
30
+ /**
31
+ * NestJS Guard for Cloudflare Access authentication.
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * import { Module } from '@nestjs/common';
36
+ * import { APP_GUARD } from '@nestjs/core';
37
+ * import { CloudflareAccessGuard } from 'cloudflare-access/adapters/nestjs';
38
+ *
39
+ * @Module({
40
+ * providers: [
41
+ * {
42
+ * provide: APP_GUARD,
43
+ * useFactory: () => new CloudflareAccessGuard({
44
+ * accessConfig: {
45
+ * teamDomain: 'https://yourteam.cloudflareaccess.com',
46
+ * audTag: 'your-audience-tag',
47
+ * },
48
+ * }),
49
+ * },
50
+ * ],
51
+ * })
52
+ * export class AppModule {}
53
+ * ```
54
+ */
55
+ declare class CloudflareAccessGuard implements CanActivate {
56
+ private readonly options;
57
+ private readonly allowedEmails;
58
+ constructor(options: CloudflareAccessGuardOptions);
59
+ canActivate(context: ExecutionContext): Promise<boolean>;
60
+ private isPublicRoute;
61
+ }
62
+
63
+ /**
64
+ * Metadata key for public routes
65
+ */
66
+ declare const IS_PUBLIC_KEY = "cfAccessPublic";
67
+
68
+ /**
69
+ * Decorator to mark a route as public (skip auth)
70
+ */
71
+ declare const Public: () => _nestjs_common.CustomDecorator<string>;
72
+ /**
73
+ * Decorator to apply Cloudflare Access authentication to a route or controller.
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * import { Controller, Get } from '@nestjs/common';
78
+ * import { CloudflareAccess, Public } from 'cloudflare-access/adapters/nestjs';
79
+ *
80
+ * @Controller('api')
81
+ * @CloudflareAccess({
82
+ * accessConfig: {
83
+ * teamDomain: 'https://yourteam.cloudflareaccess.com',
84
+ * audTag: 'your-audience-tag',
85
+ * },
86
+ * })
87
+ * export class ApiController {
88
+ * @Get('protected')
89
+ * getProtected(@Req() req: Request) {
90
+ * return { email: req.user?.email };
91
+ * }
92
+ *
93
+ * @Public()
94
+ * @Get('public')
95
+ * getPublic() {
96
+ * return { message: 'This is public' };
97
+ * }
98
+ * }
99
+ * ```
100
+ */
101
+ declare function CloudflareAccess(options: CloudflareAccessGuardOptions): <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
102
+ /**
103
+ * Interface for async options for Cloudflare Access module
104
+ */
105
+ interface CloudflareAccessModuleAsyncOptions extends Pick<ModuleMetadata, "imports"> {
106
+ useExisting?: Type<{
107
+ createCloudflareAccessOptions(): Promise<CloudflareAccessGuardOptions> | CloudflareAccessGuardOptions;
108
+ }>;
109
+ useClass?: Type<{
110
+ createCloudflareAccessOptions(): Promise<CloudflareAccessGuardOptions> | CloudflareAccessGuardOptions;
111
+ }>;
112
+ useFactory?: (...args: any[]) => Promise<CloudflareAccessGuardOptions> | CloudflareAccessGuardOptions;
113
+ inject?: any[];
114
+ }
115
+
116
+ declare module "express" {
117
+ interface Request {
118
+ /** Authenticated user from Cloudflare Access */
119
+ user?: CloudflareAccessUser;
120
+ }
121
+ }
122
+
123
+ export { CloudflareAccess, CloudflareAccessConfig, CloudflareAccessGuard, type CloudflareAccessGuardOptions, CloudflareAccessMiddlewareEnv, type CloudflareAccessModuleAsyncOptions, CloudflareAccessUser, IS_PUBLIC_KEY, Public, getCloudflareAccessConfigFromEnv };
@@ -0,0 +1,117 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+ var _chunkWUJPWM4Tjs = require('../../chunk-WUJPWM4T.js');
19
+
20
+ // src/adapters/nestjs/types.ts
21
+ function getCloudflareAccessConfigFromEnv2(env) {
22
+ return _chunkWUJPWM4Tjs.getCloudflareAccessConfigFromEnv.call(void 0, env);
23
+ }
24
+
25
+ // src/adapters/nestjs/guard.ts
26
+ var _common = require('@nestjs/common');
27
+
28
+ // src/adapters/nestjs/constants.ts
29
+ var IS_PUBLIC_KEY = "cfAccessPublic";
30
+
31
+ // src/adapters/nestjs/guard.ts
32
+ var CloudflareAccessGuard = class {
33
+ constructor(options) {
34
+ this.options = options;
35
+ this.allowedEmails = _nullishCoalesce(options.allowedEmails, () => ( null));
36
+ }
37
+
38
+
39
+ async canActivate(context) {
40
+ const isPublic = this.isPublicRoute(context);
41
+ if (isPublic) {
42
+ return true;
43
+ }
44
+ const request = context.switchToHttp().getRequest();
45
+ const method = request.method;
46
+ if (method === "OPTIONS") {
47
+ return true;
48
+ }
49
+ const protocol = request.headers["x-forwarded-proto"] || "http";
50
+ const host = request.headers.host;
51
+ const url = `${protocol}://${host}${request.originalUrl}`;
52
+ const token = request.headers["cf-access-jwt-assertion"];
53
+ const result = await _chunkWUJPWM4Tjs.validateCloudflareAccessToken.call(void 0,
54
+ token,
55
+ {
56
+ accessConfig: this.options.accessConfig,
57
+ allowedEmails: _nullishCoalesce(this.allowedEmails, () => ( void 0)),
58
+ skipInDev: this.options.skipInDev,
59
+ environment: this.options.environment
60
+ },
61
+ url
62
+ );
63
+ if (!result.success) {
64
+ if (_optionalChain([result, 'access', _ => _.error, 'optionalAccess', _2 => _2.code]) === "ACCESS_DENIED") {
65
+ throw new (0, _common.ForbiddenException)(result.error.message);
66
+ }
67
+ throw new (0, _common.UnauthorizedException)(_nullishCoalesce(_optionalChain([result, 'access', _3 => _3.error, 'optionalAccess', _4 => _4.message]), () => ( "Authentication required")));
68
+ }
69
+ if (result.user) {
70
+ request.user = result.user;
71
+ }
72
+ return true;
73
+ }
74
+ isPublicRoute(context) {
75
+ const isPublic = Reflect.getMetadata(IS_PUBLIC_KEY, context.getHandler());
76
+ if (isPublic) {
77
+ return true;
78
+ }
79
+ const isClassPublic = Reflect.getMetadata(IS_PUBLIC_KEY, context.getClass());
80
+ return _nullishCoalesce(isClassPublic, () => ( false));
81
+ }
82
+ };
83
+ CloudflareAccessGuard = exports.CloudflareAccessGuard = _chunkWUJPWM4Tjs.__decorateClass.call(void 0, [
84
+ _common.Injectable.call(void 0, )
85
+ ], CloudflareAccessGuard);
86
+
87
+ // src/adapters/nestjs/decorators.ts
88
+
89
+
90
+
91
+
92
+
93
+ var Public = () => _common.SetMetadata.call(void 0, IS_PUBLIC_KEY, true);
94
+ function CloudflareAccess(options) {
95
+ return _common.applyDecorators.call(void 0, _common.UseGuards.call(void 0, new CloudflareAccessGuard(options)));
96
+ }
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
108
+
109
+
110
+
111
+
112
+
113
+
114
+
115
+
116
+ exports.AccessDeniedError = _chunkWUJPWM4Tjs.AccessDeniedError; exports.AuthRequiredError = _chunkWUJPWM4Tjs.AuthRequiredError; exports.CloudflareAccess = CloudflareAccess; exports.CloudflareAccessError = _chunkWUJPWM4Tjs.CloudflareAccessError; exports.CloudflareAccessErrorCode = _chunkWUJPWM4Tjs.CloudflareAccessErrorCode; exports.CloudflareAccessGuard = CloudflareAccessGuard; exports.ConfigurationError = _chunkWUJPWM4Tjs.ConfigurationError; exports.IS_PUBLIC_KEY = IS_PUBLIC_KEY; exports.InvalidTokenError = _chunkWUJPWM4Tjs.InvalidTokenError; exports.Public = Public; exports.__clearJwksCache = _chunkWUJPWM4Tjs.__clearJwksCache; exports.getCloudflareAccessConfigFromEnv = getCloudflareAccessConfigFromEnv2; exports.isAccessDeniedError = _chunkWUJPWM4Tjs.isAccessDeniedError; exports.isAuthRequiredError = _chunkWUJPWM4Tjs.isAuthRequiredError; exports.isCloudflareAccessError = _chunkWUJPWM4Tjs.isCloudflareAccessError; exports.isConfigurationError = _chunkWUJPWM4Tjs.isConfigurationError; exports.isInvalidTokenError = _chunkWUJPWM4Tjs.isInvalidTokenError; exports.toAuthError = _chunkWUJPWM4Tjs.toAuthError;
117
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/v000281/personal/hono-cloudflare-access-middleware/dist/adapters/nestjs/index.js","../../../src/adapters/nestjs/types.ts","../../../src/adapters/nestjs/guard.ts","../../../src/adapters/nestjs/constants.ts","../../../src/adapters/nestjs/decorators.ts"],"names":["getCloudflareAccessConfigFromEnv"],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,0DAAgC;AAChC;AACA;ACIO,SAASA,iCAAAA,CACd,GAAA,EACwB;AACxB,EAAA,OAAO,+DAAA,GAAqC,CAAA;AAC9C;ADJA;AACA;AEvBA,wCAAsE;AFyBtE;AACA;AGxBO,IAAM,cAAA,EAAgB,gBAAA;AH0B7B;AACA;AESO,IAAM,sBAAA,EAAN,MAAmD;AAAA,EAGxD,WAAA,CAA6B,OAAA,EAAuC;AAAvC,IAAA,IAAA,CAAA,QAAA,EAAA,OAAA;AAC3B,IAAA,IAAA,CAAK,cAAA,mBAAgB,OAAA,CAAQ,aAAA,UAAiB,MAAA;AAAA,EAChD;AAAA,EAF6B;AAAA,EAFZ;AAAA,EAMjB,MAAM,WAAA,CAAY,OAAA,EAA6C;AAC7D,IAAA,MAAM,SAAA,EAAW,IAAA,CAAK,aAAA,CAAc,OAAO,CAAA;AAC3C,IAAA,GAAA,CAAI,QAAA,EAAU;AACZ,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,QAAA,EAAU,OAAA,CAAQ,YAAA,CAAa,CAAA,CAAE,UAAA,CAAoB,CAAA;AAC3D,IAAA,MAAM,OAAA,EAAS,OAAA,CAAQ,MAAA;AAGvB,IAAA,GAAA,CAAI,OAAA,IAAW,SAAA,EAAW;AACxB,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,SAAA,EAAW,OAAA,CAAQ,OAAA,CAAQ,mBAAmB,EAAA,GAAK,MAAA;AACzD,IAAA,MAAM,KAAA,EAAO,OAAA,CAAQ,OAAA,CAAQ,IAAA;AAC7B,IAAA,MAAM,IAAA,EAAM,CAAA,EAAA;AAEN,IAAA;AAEA,IAAA;AACJ,MAAA;AACA,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACA,MAAA;AACF,IAAA;AAEY,IAAA;AACC,MAAA;AACH,QAAA;AACR,MAAA;AACU,MAAA;AACZ,IAAA;AAEW,IAAA;AACD,MAAA;AACV,IAAA;AAEO,IAAA;AACT,EAAA;AAEsB,EAAA;AACd,IAAA;AACF,IAAA;AACK,MAAA;AACT,IAAA;AACM,IAAA;AACC,IAAA;AACT,EAAA;AACF;AA5Da;AADD,EAAA;AACC;AF8CI;AACA;AItFjB;AACE;AAGA;AACA;AACK;AASe;AA+BN;AACP,EAAA;AACT;AJgDiB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/Users/v000281/personal/hono-cloudflare-access-middleware/dist/adapters/nestjs/index.js","sourcesContent":[null,"import type { CloudflareAccessConfig, CloudflareAccessMiddlewareEnv } from \"../../core\";\nimport { getCloudflareAccessConfigFromEnv as _getCloudflareAccessConfigFromEnv } from \"../../core\";\n\n/**\n * Options for Cloudflare Access Guard\n */\nexport interface CloudflareAccessGuardOptions {\n /** Cloudflare Access configuration */\n accessConfig: CloudflareAccessConfig;\n\n /** Optional email allowlist. Access policy should still be configured at Cloudflare. */\n allowedEmails?: string[];\n\n /** Whether to skip JWT validation outside production */\n skipInDev?: boolean;\n\n /** Environment indicator */\n environment?: string;\n}\n\n/**\n * Get Cloudflare Access configuration from environment variables\n */\nexport function getCloudflareAccessConfigFromEnv(\n env: CloudflareAccessMiddlewareEnv,\n): CloudflareAccessConfig {\n return _getCloudflareAccessConfigFromEnv(env);\n}\n","import type { CanActivate, ExecutionContext } from \"@nestjs/common\";\nimport { Injectable, UnauthorizedException, ForbiddenException } from \"@nestjs/common\";\nimport type { Request } from \"express\";\nimport { validateCloudflareAccessToken } from \"../../core\";\nimport type { CloudflareAccessGuardOptions } from \"./types\";\nimport { IS_PUBLIC_KEY } from \"./constants\";\n\ndeclare module \"express\" {\n interface Request {\n user?: import(\"../../core\").CloudflareAccessUser;\n }\n}\n\n/**\n * NestJS Guard for Cloudflare Access authentication.\n *\n * @example\n * ```typescript\n * import { Module } from '@nestjs/common';\n * import { APP_GUARD } from '@nestjs/core';\n * import { CloudflareAccessGuard } from 'cloudflare-access/adapters/nestjs';\n *\n * @Module({\n * providers: [\n * {\n * provide: APP_GUARD,\n * useFactory: () => new CloudflareAccessGuard({\n * accessConfig: {\n * teamDomain: 'https://yourteam.cloudflareaccess.com',\n * audTag: 'your-audience-tag',\n * },\n * }),\n * },\n * ],\n * })\n * export class AppModule {}\n * ```\n */\n@Injectable()\nexport class CloudflareAccessGuard implements CanActivate {\n private readonly allowedEmails: string[] | null;\n\n constructor(private readonly options: CloudflareAccessGuardOptions) {\n this.allowedEmails = options.allowedEmails ?? null;\n }\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const isPublic = this.isPublicRoute(context);\n if (isPublic) {\n return true;\n }\n\n const request = context.switchToHttp().getRequest<Request>();\n const method = request.method;\n\n // Skip OPTIONS requests\n if (method === \"OPTIONS\") {\n return true;\n }\n\n const protocol = request.headers[\"x-forwarded-proto\"] || \"http\";\n const host = request.headers.host;\n const url = `${protocol}://${host}${request.originalUrl}`;\n\n const token = request.headers[\"cf-access-jwt-assertion\"] as string | undefined;\n\n const result = await validateCloudflareAccessToken(\n token,\n {\n accessConfig: this.options.accessConfig,\n allowedEmails: this.allowedEmails ?? undefined,\n skipInDev: this.options.skipInDev,\n environment: this.options.environment,\n },\n url,\n );\n\n if (!result.success) {\n if (result.error?.code === \"ACCESS_DENIED\") {\n throw new ForbiddenException(result.error.message);\n }\n throw new UnauthorizedException(result.error?.message ?? \"Authentication required\");\n }\n\n if (result.user) {\n request.user = result.user;\n }\n\n return true;\n }\n\n private isPublicRoute(context: ExecutionContext): boolean {\n const isPublic = Reflect.getMetadata(IS_PUBLIC_KEY, context.getHandler());\n if (isPublic) {\n return true;\n }\n const isClassPublic = Reflect.getMetadata(IS_PUBLIC_KEY, context.getClass());\n return isClassPublic ?? false;\n }\n}\n","/**\n * Metadata key for public routes\n */\nexport const IS_PUBLIC_KEY = \"cfAccessPublic\";\n","import {\n SetMetadata,\n type ModuleMetadata,\n type Type,\n applyDecorators,\n UseGuards,\n} from \"@nestjs/common\";\nimport { CloudflareAccessGuard } from \"./guard\";\nimport type { CloudflareAccessGuardOptions } from \"./types\";\nimport { IS_PUBLIC_KEY } from \"./constants\";\nexport { IS_PUBLIC_KEY } from \"./constants\";\n\n/**\n * Decorator to mark a route as public (skip auth)\n */\nexport const Public = () => SetMetadata(IS_PUBLIC_KEY, true);\n\n/**\n * Decorator to apply Cloudflare Access authentication to a route or controller.\n *\n * @example\n * ```typescript\n * import { Controller, Get } from '@nestjs/common';\n * import { CloudflareAccess, Public } from 'cloudflare-access/adapters/nestjs';\n *\n * @Controller('api')\n * @CloudflareAccess({\n * accessConfig: {\n * teamDomain: 'https://yourteam.cloudflareaccess.com',\n * audTag: 'your-audience-tag',\n * },\n * })\n * export class ApiController {\n * @Get('protected')\n * getProtected(@Req() req: Request) {\n * return { email: req.user?.email };\n * }\n *\n * @Public()\n * @Get('public')\n * getPublic() {\n * return { message: 'This is public' };\n * }\n * }\n * ```\n */\nexport function CloudflareAccess(options: CloudflareAccessGuardOptions) {\n return applyDecorators(UseGuards(new CloudflareAccessGuard(options)));\n}\n\n/**\n * Interface for async options for Cloudflare Access module\n */\nexport interface CloudflareAccessModuleAsyncOptions extends Pick<ModuleMetadata, \"imports\"> {\n useExisting?: Type<{\n createCloudflareAccessOptions():\n | Promise<CloudflareAccessGuardOptions>\n | CloudflareAccessGuardOptions;\n }>;\n useClass?: Type<{\n createCloudflareAccessOptions():\n | Promise<CloudflareAccessGuardOptions>\n | CloudflareAccessGuardOptions;\n }>;\n useFactory?: (\n ...args: any[]\n ) => Promise<CloudflareAccessGuardOptions> | CloudflareAccessGuardOptions;\n inject?: any[];\n}\n"]}
@@ -0,0 +1,117 @@
1
+ import {
2
+ AccessDeniedError,
3
+ AuthRequiredError,
4
+ CloudflareAccessError,
5
+ CloudflareAccessErrorCode,
6
+ ConfigurationError,
7
+ InvalidTokenError,
8
+ __clearJwksCache,
9
+ __decorateClass,
10
+ getCloudflareAccessConfigFromEnv,
11
+ isAccessDeniedError,
12
+ isAuthRequiredError,
13
+ isCloudflareAccessError,
14
+ isConfigurationError,
15
+ isInvalidTokenError,
16
+ toAuthError,
17
+ validateCloudflareAccessToken
18
+ } from "../../chunk-DM2KGIQX.mjs";
19
+
20
+ // src/adapters/nestjs/types.ts
21
+ function getCloudflareAccessConfigFromEnv2(env) {
22
+ return getCloudflareAccessConfigFromEnv(env);
23
+ }
24
+
25
+ // src/adapters/nestjs/guard.ts
26
+ import { Injectable, UnauthorizedException, ForbiddenException } from "@nestjs/common";
27
+
28
+ // src/adapters/nestjs/constants.ts
29
+ var IS_PUBLIC_KEY = "cfAccessPublic";
30
+
31
+ // src/adapters/nestjs/guard.ts
32
+ var CloudflareAccessGuard = class {
33
+ constructor(options) {
34
+ this.options = options;
35
+ this.allowedEmails = options.allowedEmails ?? null;
36
+ }
37
+ options;
38
+ allowedEmails;
39
+ async canActivate(context) {
40
+ const isPublic = this.isPublicRoute(context);
41
+ if (isPublic) {
42
+ return true;
43
+ }
44
+ const request = context.switchToHttp().getRequest();
45
+ const method = request.method;
46
+ if (method === "OPTIONS") {
47
+ return true;
48
+ }
49
+ const protocol = request.headers["x-forwarded-proto"] || "http";
50
+ const host = request.headers.host;
51
+ const url = `${protocol}://${host}${request.originalUrl}`;
52
+ const token = request.headers["cf-access-jwt-assertion"];
53
+ const result = await validateCloudflareAccessToken(
54
+ token,
55
+ {
56
+ accessConfig: this.options.accessConfig,
57
+ allowedEmails: this.allowedEmails ?? void 0,
58
+ skipInDev: this.options.skipInDev,
59
+ environment: this.options.environment
60
+ },
61
+ url
62
+ );
63
+ if (!result.success) {
64
+ if (result.error?.code === "ACCESS_DENIED") {
65
+ throw new ForbiddenException(result.error.message);
66
+ }
67
+ throw new UnauthorizedException(result.error?.message ?? "Authentication required");
68
+ }
69
+ if (result.user) {
70
+ request.user = result.user;
71
+ }
72
+ return true;
73
+ }
74
+ isPublicRoute(context) {
75
+ const isPublic = Reflect.getMetadata(IS_PUBLIC_KEY, context.getHandler());
76
+ if (isPublic) {
77
+ return true;
78
+ }
79
+ const isClassPublic = Reflect.getMetadata(IS_PUBLIC_KEY, context.getClass());
80
+ return isClassPublic ?? false;
81
+ }
82
+ };
83
+ CloudflareAccessGuard = __decorateClass([
84
+ Injectable()
85
+ ], CloudflareAccessGuard);
86
+
87
+ // src/adapters/nestjs/decorators.ts
88
+ import {
89
+ SetMetadata,
90
+ applyDecorators,
91
+ UseGuards
92
+ } from "@nestjs/common";
93
+ var Public = () => SetMetadata(IS_PUBLIC_KEY, true);
94
+ function CloudflareAccess(options) {
95
+ return applyDecorators(UseGuards(new CloudflareAccessGuard(options)));
96
+ }
97
+ export {
98
+ AccessDeniedError,
99
+ AuthRequiredError,
100
+ CloudflareAccess,
101
+ CloudflareAccessError,
102
+ CloudflareAccessErrorCode,
103
+ CloudflareAccessGuard,
104
+ ConfigurationError,
105
+ IS_PUBLIC_KEY,
106
+ InvalidTokenError,
107
+ Public,
108
+ __clearJwksCache,
109
+ getCloudflareAccessConfigFromEnv2 as getCloudflareAccessConfigFromEnv,
110
+ isAccessDeniedError,
111
+ isAuthRequiredError,
112
+ isCloudflareAccessError,
113
+ isConfigurationError,
114
+ isInvalidTokenError,
115
+ toAuthError
116
+ };
117
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/nestjs/types.ts","../../../src/adapters/nestjs/guard.ts","../../../src/adapters/nestjs/constants.ts","../../../src/adapters/nestjs/decorators.ts"],"sourcesContent":["import type { CloudflareAccessConfig, CloudflareAccessMiddlewareEnv } from \"../../core\";\nimport { getCloudflareAccessConfigFromEnv as _getCloudflareAccessConfigFromEnv } from \"../../core\";\n\n/**\n * Options for Cloudflare Access Guard\n */\nexport interface CloudflareAccessGuardOptions {\n /** Cloudflare Access configuration */\n accessConfig: CloudflareAccessConfig;\n\n /** Optional email allowlist. Access policy should still be configured at Cloudflare. */\n allowedEmails?: string[];\n\n /** Whether to skip JWT validation outside production */\n skipInDev?: boolean;\n\n /** Environment indicator */\n environment?: string;\n}\n\n/**\n * Get Cloudflare Access configuration from environment variables\n */\nexport function getCloudflareAccessConfigFromEnv(\n env: CloudflareAccessMiddlewareEnv,\n): CloudflareAccessConfig {\n return _getCloudflareAccessConfigFromEnv(env);\n}\n","import type { CanActivate, ExecutionContext } from \"@nestjs/common\";\nimport { Injectable, UnauthorizedException, ForbiddenException } from \"@nestjs/common\";\nimport type { Request } from \"express\";\nimport { validateCloudflareAccessToken } from \"../../core\";\nimport type { CloudflareAccessGuardOptions } from \"./types\";\nimport { IS_PUBLIC_KEY } from \"./constants\";\n\ndeclare module \"express\" {\n interface Request {\n user?: import(\"../../core\").CloudflareAccessUser;\n }\n}\n\n/**\n * NestJS Guard for Cloudflare Access authentication.\n *\n * @example\n * ```typescript\n * import { Module } from '@nestjs/common';\n * import { APP_GUARD } from '@nestjs/core';\n * import { CloudflareAccessGuard } from 'cloudflare-access/adapters/nestjs';\n *\n * @Module({\n * providers: [\n * {\n * provide: APP_GUARD,\n * useFactory: () => new CloudflareAccessGuard({\n * accessConfig: {\n * teamDomain: 'https://yourteam.cloudflareaccess.com',\n * audTag: 'your-audience-tag',\n * },\n * }),\n * },\n * ],\n * })\n * export class AppModule {}\n * ```\n */\n@Injectable()\nexport class CloudflareAccessGuard implements CanActivate {\n private readonly allowedEmails: string[] | null;\n\n constructor(private readonly options: CloudflareAccessGuardOptions) {\n this.allowedEmails = options.allowedEmails ?? null;\n }\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const isPublic = this.isPublicRoute(context);\n if (isPublic) {\n return true;\n }\n\n const request = context.switchToHttp().getRequest<Request>();\n const method = request.method;\n\n // Skip OPTIONS requests\n if (method === \"OPTIONS\") {\n return true;\n }\n\n const protocol = request.headers[\"x-forwarded-proto\"] || \"http\";\n const host = request.headers.host;\n const url = `${protocol}://${host}${request.originalUrl}`;\n\n const token = request.headers[\"cf-access-jwt-assertion\"] as string | undefined;\n\n const result = await validateCloudflareAccessToken(\n token,\n {\n accessConfig: this.options.accessConfig,\n allowedEmails: this.allowedEmails ?? undefined,\n skipInDev: this.options.skipInDev,\n environment: this.options.environment,\n },\n url,\n );\n\n if (!result.success) {\n if (result.error?.code === \"ACCESS_DENIED\") {\n throw new ForbiddenException(result.error.message);\n }\n throw new UnauthorizedException(result.error?.message ?? \"Authentication required\");\n }\n\n if (result.user) {\n request.user = result.user;\n }\n\n return true;\n }\n\n private isPublicRoute(context: ExecutionContext): boolean {\n const isPublic = Reflect.getMetadata(IS_PUBLIC_KEY, context.getHandler());\n if (isPublic) {\n return true;\n }\n const isClassPublic = Reflect.getMetadata(IS_PUBLIC_KEY, context.getClass());\n return isClassPublic ?? false;\n }\n}\n","/**\n * Metadata key for public routes\n */\nexport const IS_PUBLIC_KEY = \"cfAccessPublic\";\n","import {\n SetMetadata,\n type ModuleMetadata,\n type Type,\n applyDecorators,\n UseGuards,\n} from \"@nestjs/common\";\nimport { CloudflareAccessGuard } from \"./guard\";\nimport type { CloudflareAccessGuardOptions } from \"./types\";\nimport { IS_PUBLIC_KEY } from \"./constants\";\nexport { IS_PUBLIC_KEY } from \"./constants\";\n\n/**\n * Decorator to mark a route as public (skip auth)\n */\nexport const Public = () => SetMetadata(IS_PUBLIC_KEY, true);\n\n/**\n * Decorator to apply Cloudflare Access authentication to a route or controller.\n *\n * @example\n * ```typescript\n * import { Controller, Get } from '@nestjs/common';\n * import { CloudflareAccess, Public } from 'cloudflare-access/adapters/nestjs';\n *\n * @Controller('api')\n * @CloudflareAccess({\n * accessConfig: {\n * teamDomain: 'https://yourteam.cloudflareaccess.com',\n * audTag: 'your-audience-tag',\n * },\n * })\n * export class ApiController {\n * @Get('protected')\n * getProtected(@Req() req: Request) {\n * return { email: req.user?.email };\n * }\n *\n * @Public()\n * @Get('public')\n * getPublic() {\n * return { message: 'This is public' };\n * }\n * }\n * ```\n */\nexport function CloudflareAccess(options: CloudflareAccessGuardOptions) {\n return applyDecorators(UseGuards(new CloudflareAccessGuard(options)));\n}\n\n/**\n * Interface for async options for Cloudflare Access module\n */\nexport interface CloudflareAccessModuleAsyncOptions extends Pick<ModuleMetadata, \"imports\"> {\n useExisting?: Type<{\n createCloudflareAccessOptions():\n | Promise<CloudflareAccessGuardOptions>\n | CloudflareAccessGuardOptions;\n }>;\n useClass?: Type<{\n createCloudflareAccessOptions():\n | Promise<CloudflareAccessGuardOptions>\n | CloudflareAccessGuardOptions;\n }>;\n useFactory?: (\n ...args: any[]\n ) => Promise<CloudflareAccessGuardOptions> | CloudflareAccessGuardOptions;\n inject?: any[];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAuBO,SAASA,kCACd,KACwB;AACxB,SAAO,iCAAkC,GAAG;AAC9C;;;AC1BA,SAAS,YAAY,uBAAuB,0BAA0B;;;ACE/D,IAAM,gBAAgB;;;ADoCtB,IAAM,wBAAN,MAAmD;AAAA,EAGxD,YAA6B,SAAuC;AAAvC;AAC3B,SAAK,gBAAgB,QAAQ,iBAAiB;AAAA,EAChD;AAAA,EAF6B;AAAA,EAFZ;AAAA,EAMjB,MAAM,YAAY,SAA6C;AAC7D,UAAM,WAAW,KAAK,cAAc,OAAO;AAC3C,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,QAAQ,aAAa,EAAE,WAAoB;AAC3D,UAAM,SAAS,QAAQ;AAGvB,QAAI,WAAW,WAAW;AACxB,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,QAAQ,QAAQ,mBAAmB,KAAK;AACzD,UAAM,OAAO,QAAQ,QAAQ;AAC7B,UAAM,MAAM,GAAG,QAAQ,MAAM,IAAI,GAAG,QAAQ,WAAW;AAEvD,UAAM,QAAQ,QAAQ,QAAQ,yBAAyB;AAEvD,UAAM,SAAS,MAAM;AAAA,MACnB;AAAA,MACA;AAAA,QACE,cAAc,KAAK,QAAQ;AAAA,QAC3B,eAAe,KAAK,iBAAiB;AAAA,QACrC,WAAW,KAAK,QAAQ;AAAA,QACxB,aAAa,KAAK,QAAQ;AAAA,MAC5B;AAAA,MACA;AAAA,IACF;AAEA,QAAI,CAAC,OAAO,SAAS;AACnB,UAAI,OAAO,OAAO,SAAS,iBAAiB;AAC1C,cAAM,IAAI,mBAAmB,OAAO,MAAM,OAAO;AAAA,MACnD;AACA,YAAM,IAAI,sBAAsB,OAAO,OAAO,WAAW,yBAAyB;AAAA,IACpF;AAEA,QAAI,OAAO,MAAM;AACf,cAAQ,OAAO,OAAO;AAAA,IACxB;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,cAAc,SAAoC;AACxD,UAAM,WAAW,QAAQ,YAAY,eAAe,QAAQ,WAAW,CAAC;AACxE,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AACA,UAAM,gBAAgB,QAAQ,YAAY,eAAe,QAAQ,SAAS,CAAC;AAC3E,WAAO,iBAAiB;AAAA,EAC1B;AACF;AA5Da,wBAAN;AAAA,EADN,WAAW;AAAA,GACC;;;AEvCb;AAAA,EACE;AAAA,EAGA;AAAA,EACA;AAAA,OACK;AASA,IAAM,SAAS,MAAM,YAAY,eAAe,IAAI;AA+BpD,SAAS,iBAAiB,SAAuC;AACtE,SAAO,gBAAgB,UAAU,IAAI,sBAAsB,OAAO,CAAC,CAAC;AACtE;","names":["getCloudflareAccessConfigFromEnv"]}