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,173 @@
1
+ import { JWTPayload, createRemoteJWKSet } from 'jose';
2
+
3
+ /**
4
+ * Cloudflare Access JWT payload with additional claims
5
+ */
6
+ interface CloudflareAccessPayload extends JWTPayload {
7
+ /** User's email address */
8
+ email?: string;
9
+ /** Token type */
10
+ type?: string;
11
+ /** Identity nonce for additional verification */
12
+ identity_nonce?: string;
13
+ /** User's country */
14
+ country?: string;
15
+ }
16
+ /**
17
+ * Cloudflare Access configuration
18
+ */
19
+ interface CloudflareAccessConfig {
20
+ /** Exact Cloudflare Access issuer domain, e.g. https://myteam.cloudflareaccess.com */
21
+ teamDomain: string;
22
+ /** Exact Access application audience tag */
23
+ audTag: string;
24
+ }
25
+ /**
26
+ * User information extracted from Cloudflare Access token
27
+ */
28
+ interface CloudflareAccessUser {
29
+ email: string;
30
+ userId?: string;
31
+ country?: string;
32
+ }
33
+ /**
34
+ * Expected environment bindings for Cloudflare Access
35
+ */
36
+ interface CloudflareAccessMiddlewareEnv {
37
+ CF_ACCESS_TEAM_DOMAIN?: string;
38
+ CF_ACCESS_AUD?: string;
39
+ ENVIRONMENT?: string;
40
+ }
41
+ /**
42
+ * Error codes for Cloudflare Access authentication
43
+ */
44
+ declare const CloudflareAccessErrorCode: {
45
+ /** Missing or invalid authentication token */
46
+ readonly AUTH_REQUIRED: "AUTH_REQUIRED";
47
+ /** Token validation failed (expired, wrong signature, etc.) */
48
+ readonly INVALID_TOKEN: "INVALID_TOKEN";
49
+ /** User email not in allowlist */
50
+ readonly ACCESS_DENIED: "ACCESS_DENIED";
51
+ /** Invalid team domain configuration */
52
+ readonly INVALID_TEAM_DOMAIN: "INVALID_TEAM_DOMAIN";
53
+ /** Missing audience tag configuration */
54
+ readonly MISSING_AUDIENCE_TAG: "MISSING_AUDIENCE_TAG";
55
+ /** Missing environment configuration */
56
+ readonly MISSING_CONFIG: "MISSING_CONFIG";
57
+ /** JWKS fetch failed */
58
+ readonly JWKS_FETCH_ERROR: "JWKS_FETCH_ERROR";
59
+ };
60
+ type CloudflareAccessErrorCode = (typeof CloudflareAccessErrorCode)[keyof typeof CloudflareAccessErrorCode];
61
+ /**
62
+ * Rich authentication error with actionable information
63
+ */
64
+ interface AuthError {
65
+ code: CloudflareAccessErrorCode;
66
+ message: string;
67
+ why: string;
68
+ fix: string;
69
+ context?: Record<string, unknown>;
70
+ }
71
+ /**
72
+ * Authentication result
73
+ */
74
+ type AuthResult = {
75
+ success: true;
76
+ user: CloudflareAccessUser | null;
77
+ error?: never;
78
+ } | {
79
+ success: false;
80
+ user?: CloudflareAccessUser | null;
81
+ error: AuthError;
82
+ };
83
+
84
+ /**
85
+ * Base error class for Cloudflare Access authentication errors
86
+ */
87
+ declare class CloudflareAccessError extends Error {
88
+ readonly code: CloudflareAccessErrorCode;
89
+ readonly context?: Record<string, unknown>;
90
+ readonly requestUrl?: string;
91
+ readonly timestamp: string;
92
+ constructor(code: CloudflareAccessErrorCode, message: string, options?: {
93
+ cause?: Error;
94
+ context?: Record<string, unknown>;
95
+ requestUrl?: string;
96
+ });
97
+ /**
98
+ * Get a user-friendly error message with fix instructions
99
+ */
100
+ toJSON(): Record<string, unknown>;
101
+ /**
102
+ * Get fix instructions based on error code
103
+ */
104
+ private getFixInstructions;
105
+ }
106
+ /**
107
+ * Error thrown when authentication is required but missing/invalid
108
+ */
109
+ declare class AuthRequiredError extends CloudflareAccessError {
110
+ constructor(options?: {
111
+ requestUrl?: string;
112
+ context?: Record<string, unknown>;
113
+ });
114
+ }
115
+ /**
116
+ * Error thrown when token validation fails
117
+ */
118
+ declare class InvalidTokenError extends CloudflareAccessError {
119
+ readonly reason: string;
120
+ constructor(reason: string, options?: {
121
+ requestUrl?: string;
122
+ });
123
+ }
124
+ /**
125
+ * Error thrown when user is not in email allowlist
126
+ */
127
+ declare class AccessDeniedError extends CloudflareAccessError {
128
+ readonly email: string;
129
+ constructor(email: string, options?: {
130
+ requestUrl?: string;
131
+ allowedEmails?: string[];
132
+ });
133
+ }
134
+ /**
135
+ * Error thrown when configuration is invalid or missing
136
+ */
137
+ declare class ConfigurationError extends CloudflareAccessError {
138
+ constructor(message: string, options?: {
139
+ cause?: Error;
140
+ context?: Record<string, unknown>;
141
+ });
142
+ }
143
+ /**
144
+ * Type guard to check if error is a CloudflareAccessError
145
+ */
146
+ declare function isCloudflareAccessError(error: unknown): error is CloudflareAccessError;
147
+ /**
148
+ * Type guard for specific error types
149
+ */
150
+ declare function isAuthRequiredError(error: unknown): error is AuthRequiredError;
151
+ declare function isInvalidTokenError(error: unknown): error is InvalidTokenError;
152
+ declare function isAccessDeniedError(error: unknown): error is AccessDeniedError;
153
+ declare function isConfigurationError(error: unknown): error is ConfigurationError;
154
+ /**
155
+ * Convert unknown error to CloudflareAccessError
156
+ */
157
+ declare function toAuthError(error: unknown): CloudflareAccessError;
158
+
159
+ /**
160
+ * Clear the JWKS cache. Useful for testing.
161
+ * @internal
162
+ */
163
+ declare function __clearJwksCache(): void;
164
+ /**
165
+ * Get or create cached JWKS for a team domain
166
+ */
167
+ declare function getRemoteJwks(teamDomain: string): ReturnType<typeof createRemoteJWKSet>;
168
+ /**
169
+ * Check if request is from local development
170
+ */
171
+ declare function isLocalDevelopmentRequest(url: string): boolean;
172
+
173
+ export { AccessDeniedError as A, type CloudflareAccessConfig as C, InvalidTokenError as I, __clearJwksCache as _, AuthRequiredError as a, type AuthResult as b, CloudflareAccessError as c, CloudflareAccessErrorCode as d, type CloudflareAccessMiddlewareEnv as e, type CloudflareAccessPayload as f, type CloudflareAccessUser as g, ConfigurationError as h, isAccessDeniedError as i, isAuthRequiredError as j, isCloudflareAccessError as k, isConfigurationError as l, isInvalidTokenError as m, type AuthError as n, getRemoteJwks as o, isLocalDevelopmentRequest as p, toAuthError as t };
@@ -0,0 +1,173 @@
1
+ import { JWTPayload, createRemoteJWKSet } from 'jose';
2
+
3
+ /**
4
+ * Cloudflare Access JWT payload with additional claims
5
+ */
6
+ interface CloudflareAccessPayload extends JWTPayload {
7
+ /** User's email address */
8
+ email?: string;
9
+ /** Token type */
10
+ type?: string;
11
+ /** Identity nonce for additional verification */
12
+ identity_nonce?: string;
13
+ /** User's country */
14
+ country?: string;
15
+ }
16
+ /**
17
+ * Cloudflare Access configuration
18
+ */
19
+ interface CloudflareAccessConfig {
20
+ /** Exact Cloudflare Access issuer domain, e.g. https://myteam.cloudflareaccess.com */
21
+ teamDomain: string;
22
+ /** Exact Access application audience tag */
23
+ audTag: string;
24
+ }
25
+ /**
26
+ * User information extracted from Cloudflare Access token
27
+ */
28
+ interface CloudflareAccessUser {
29
+ email: string;
30
+ userId?: string;
31
+ country?: string;
32
+ }
33
+ /**
34
+ * Expected environment bindings for Cloudflare Access
35
+ */
36
+ interface CloudflareAccessMiddlewareEnv {
37
+ CF_ACCESS_TEAM_DOMAIN?: string;
38
+ CF_ACCESS_AUD?: string;
39
+ ENVIRONMENT?: string;
40
+ }
41
+ /**
42
+ * Error codes for Cloudflare Access authentication
43
+ */
44
+ declare const CloudflareAccessErrorCode: {
45
+ /** Missing or invalid authentication token */
46
+ readonly AUTH_REQUIRED: "AUTH_REQUIRED";
47
+ /** Token validation failed (expired, wrong signature, etc.) */
48
+ readonly INVALID_TOKEN: "INVALID_TOKEN";
49
+ /** User email not in allowlist */
50
+ readonly ACCESS_DENIED: "ACCESS_DENIED";
51
+ /** Invalid team domain configuration */
52
+ readonly INVALID_TEAM_DOMAIN: "INVALID_TEAM_DOMAIN";
53
+ /** Missing audience tag configuration */
54
+ readonly MISSING_AUDIENCE_TAG: "MISSING_AUDIENCE_TAG";
55
+ /** Missing environment configuration */
56
+ readonly MISSING_CONFIG: "MISSING_CONFIG";
57
+ /** JWKS fetch failed */
58
+ readonly JWKS_FETCH_ERROR: "JWKS_FETCH_ERROR";
59
+ };
60
+ type CloudflareAccessErrorCode = (typeof CloudflareAccessErrorCode)[keyof typeof CloudflareAccessErrorCode];
61
+ /**
62
+ * Rich authentication error with actionable information
63
+ */
64
+ interface AuthError {
65
+ code: CloudflareAccessErrorCode;
66
+ message: string;
67
+ why: string;
68
+ fix: string;
69
+ context?: Record<string, unknown>;
70
+ }
71
+ /**
72
+ * Authentication result
73
+ */
74
+ type AuthResult = {
75
+ success: true;
76
+ user: CloudflareAccessUser | null;
77
+ error?: never;
78
+ } | {
79
+ success: false;
80
+ user?: CloudflareAccessUser | null;
81
+ error: AuthError;
82
+ };
83
+
84
+ /**
85
+ * Base error class for Cloudflare Access authentication errors
86
+ */
87
+ declare class CloudflareAccessError extends Error {
88
+ readonly code: CloudflareAccessErrorCode;
89
+ readonly context?: Record<string, unknown>;
90
+ readonly requestUrl?: string;
91
+ readonly timestamp: string;
92
+ constructor(code: CloudflareAccessErrorCode, message: string, options?: {
93
+ cause?: Error;
94
+ context?: Record<string, unknown>;
95
+ requestUrl?: string;
96
+ });
97
+ /**
98
+ * Get a user-friendly error message with fix instructions
99
+ */
100
+ toJSON(): Record<string, unknown>;
101
+ /**
102
+ * Get fix instructions based on error code
103
+ */
104
+ private getFixInstructions;
105
+ }
106
+ /**
107
+ * Error thrown when authentication is required but missing/invalid
108
+ */
109
+ declare class AuthRequiredError extends CloudflareAccessError {
110
+ constructor(options?: {
111
+ requestUrl?: string;
112
+ context?: Record<string, unknown>;
113
+ });
114
+ }
115
+ /**
116
+ * Error thrown when token validation fails
117
+ */
118
+ declare class InvalidTokenError extends CloudflareAccessError {
119
+ readonly reason: string;
120
+ constructor(reason: string, options?: {
121
+ requestUrl?: string;
122
+ });
123
+ }
124
+ /**
125
+ * Error thrown when user is not in email allowlist
126
+ */
127
+ declare class AccessDeniedError extends CloudflareAccessError {
128
+ readonly email: string;
129
+ constructor(email: string, options?: {
130
+ requestUrl?: string;
131
+ allowedEmails?: string[];
132
+ });
133
+ }
134
+ /**
135
+ * Error thrown when configuration is invalid or missing
136
+ */
137
+ declare class ConfigurationError extends CloudflareAccessError {
138
+ constructor(message: string, options?: {
139
+ cause?: Error;
140
+ context?: Record<string, unknown>;
141
+ });
142
+ }
143
+ /**
144
+ * Type guard to check if error is a CloudflareAccessError
145
+ */
146
+ declare function isCloudflareAccessError(error: unknown): error is CloudflareAccessError;
147
+ /**
148
+ * Type guard for specific error types
149
+ */
150
+ declare function isAuthRequiredError(error: unknown): error is AuthRequiredError;
151
+ declare function isInvalidTokenError(error: unknown): error is InvalidTokenError;
152
+ declare function isAccessDeniedError(error: unknown): error is AccessDeniedError;
153
+ declare function isConfigurationError(error: unknown): error is ConfigurationError;
154
+ /**
155
+ * Convert unknown error to CloudflareAccessError
156
+ */
157
+ declare function toAuthError(error: unknown): CloudflareAccessError;
158
+
159
+ /**
160
+ * Clear the JWKS cache. Useful for testing.
161
+ * @internal
162
+ */
163
+ declare function __clearJwksCache(): void;
164
+ /**
165
+ * Get or create cached JWKS for a team domain
166
+ */
167
+ declare function getRemoteJwks(teamDomain: string): ReturnType<typeof createRemoteJWKSet>;
168
+ /**
169
+ * Check if request is from local development
170
+ */
171
+ declare function isLocalDevelopmentRequest(url: string): boolean;
172
+
173
+ export { AccessDeniedError as A, type CloudflareAccessConfig as C, InvalidTokenError as I, __clearJwksCache as _, AuthRequiredError as a, type AuthResult as b, CloudflareAccessError as c, CloudflareAccessErrorCode as d, type CloudflareAccessMiddlewareEnv as e, type CloudflareAccessPayload as f, type CloudflareAccessUser as g, ConfigurationError as h, isAccessDeniedError as i, isAuthRequiredError as j, isCloudflareAccessError as k, isConfigurationError as l, isInvalidTokenError as m, type AuthError as n, getRemoteJwks as o, isLocalDevelopmentRequest as p, toAuthError as t };
@@ -0,0 +1,83 @@
1
+ import * as hono from 'hono';
2
+ import { Context, MiddlewareHandler } from 'hono';
3
+ import { C as CloudflareAccessConfig, g as CloudflareAccessUser, e as CloudflareAccessMiddlewareEnv } from './jwks-ChdyyS_L.mjs';
4
+
5
+ /**
6
+ * Extended Hono variables type
7
+ */
8
+ interface CloudflareAccessVariables {
9
+ /** Authenticated user from Cloudflare Access */
10
+ user?: CloudflareAccessUser;
11
+ }
12
+ /**
13
+ * Helper type to create a typed Hono app with Cloudflare Access variables
14
+ */
15
+ type CloudflareAccessHono = hono.Hono<{
16
+ Variables: CloudflareAccessVariables;
17
+ }>;
18
+ /**
19
+ * Configuration resolver type - can be static config or a function
20
+ */
21
+ type CloudflareAccessConfigResolver$1 = CloudflareAccessConfig | ((c: Context) => CloudflareAccessConfig);
22
+ /**
23
+ * Options for creating Cloudflare Access authentication middleware for Hono
24
+ */
25
+ interface CloudflareAccessAuthOptions {
26
+ /**
27
+ * Exact Cloudflare Access config or a resolver that reads it from bindings.
28
+ * Both `teamDomain` and `audTag` are required for secure validation.
29
+ */
30
+ accessConfig: CloudflareAccessConfigResolver$1;
31
+ /** Optional email allowlist. Access policy should still be configured at Cloudflare. */
32
+ allowedEmails?: string[];
33
+ /** Custom unauthorized handler */
34
+ onUnauthorized?: (c: Context, reason: string) => Response | Promise<Response>;
35
+ /** Custom forbidden handler */
36
+ onForbidden?: (c: Context, email: string) => Response | Promise<Response>;
37
+ /** Paths to exclude from auth check */
38
+ excludePaths?: string[];
39
+ /** Whether to skip JWT validation outside production */
40
+ skipInDev?: boolean;
41
+ }
42
+
43
+ /**
44
+ * Configuration resolver type - can be static config or a function
45
+ */
46
+ type CloudflareAccessConfigResolver = CloudflareAccessConfig | ((c: Context) => CloudflareAccessConfig);
47
+ /**
48
+ * Get Cloudflare Access configuration from Hono context bindings
49
+ */
50
+ declare function getCloudflareAccessConfigFromBindings(c: Context<{
51
+ Bindings: CloudflareAccessMiddlewareEnv;
52
+ }>): CloudflareAccessConfig;
53
+ /**
54
+ * Get access configuration from resolver
55
+ */
56
+ declare function resolveConfig(resolver: CloudflareAccessConfigResolver, c: Context): CloudflareAccessConfig;
57
+
58
+ /**
59
+ * Creates secure Cloudflare Access authentication middleware for Hono.
60
+ *
61
+ * @param options - Configuration options
62
+ * @returns Hono middleware handler
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * import { Hono } from 'hono';
67
+ * import { createCloudflareAccessAuth, getCloudflareAccessConfigFromBindings } from 'cloudflare-access/adapters/hono';
68
+ *
69
+ * const app = new Hono();
70
+ *
71
+ * app.use(createCloudflareAccessAuth({
72
+ * accessConfig: getCloudflareAccessConfigFromBindings,
73
+ * }));
74
+ *
75
+ * app.get('/protected', (c) => {
76
+ * const user = c.get('user');
77
+ * return c.json({ email: user?.email });
78
+ * });
79
+ * ```
80
+ */
81
+ declare function createCloudflareAccessAuth(options: CloudflareAccessAuthOptions): MiddlewareHandler;
82
+
83
+ export { type CloudflareAccessAuthOptions as C, type CloudflareAccessConfigResolver$1 as a, type CloudflareAccessHono as b, type CloudflareAccessVariables as c, createCloudflareAccessAuth as d, getCloudflareAccessConfigFromBindings as g, resolveConfig as r };
@@ -0,0 +1,83 @@
1
+ import * as hono from 'hono';
2
+ import { Context, MiddlewareHandler } from 'hono';
3
+ import { C as CloudflareAccessConfig, g as CloudflareAccessUser, e as CloudflareAccessMiddlewareEnv } from './jwks-ChdyyS_L.js';
4
+
5
+ /**
6
+ * Extended Hono variables type
7
+ */
8
+ interface CloudflareAccessVariables {
9
+ /** Authenticated user from Cloudflare Access */
10
+ user?: CloudflareAccessUser;
11
+ }
12
+ /**
13
+ * Helper type to create a typed Hono app with Cloudflare Access variables
14
+ */
15
+ type CloudflareAccessHono = hono.Hono<{
16
+ Variables: CloudflareAccessVariables;
17
+ }>;
18
+ /**
19
+ * Configuration resolver type - can be static config or a function
20
+ */
21
+ type CloudflareAccessConfigResolver$1 = CloudflareAccessConfig | ((c: Context) => CloudflareAccessConfig);
22
+ /**
23
+ * Options for creating Cloudflare Access authentication middleware for Hono
24
+ */
25
+ interface CloudflareAccessAuthOptions {
26
+ /**
27
+ * Exact Cloudflare Access config or a resolver that reads it from bindings.
28
+ * Both `teamDomain` and `audTag` are required for secure validation.
29
+ */
30
+ accessConfig: CloudflareAccessConfigResolver$1;
31
+ /** Optional email allowlist. Access policy should still be configured at Cloudflare. */
32
+ allowedEmails?: string[];
33
+ /** Custom unauthorized handler */
34
+ onUnauthorized?: (c: Context, reason: string) => Response | Promise<Response>;
35
+ /** Custom forbidden handler */
36
+ onForbidden?: (c: Context, email: string) => Response | Promise<Response>;
37
+ /** Paths to exclude from auth check */
38
+ excludePaths?: string[];
39
+ /** Whether to skip JWT validation outside production */
40
+ skipInDev?: boolean;
41
+ }
42
+
43
+ /**
44
+ * Configuration resolver type - can be static config or a function
45
+ */
46
+ type CloudflareAccessConfigResolver = CloudflareAccessConfig | ((c: Context) => CloudflareAccessConfig);
47
+ /**
48
+ * Get Cloudflare Access configuration from Hono context bindings
49
+ */
50
+ declare function getCloudflareAccessConfigFromBindings(c: Context<{
51
+ Bindings: CloudflareAccessMiddlewareEnv;
52
+ }>): CloudflareAccessConfig;
53
+ /**
54
+ * Get access configuration from resolver
55
+ */
56
+ declare function resolveConfig(resolver: CloudflareAccessConfigResolver, c: Context): CloudflareAccessConfig;
57
+
58
+ /**
59
+ * Creates secure Cloudflare Access authentication middleware for Hono.
60
+ *
61
+ * @param options - Configuration options
62
+ * @returns Hono middleware handler
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * import { Hono } from 'hono';
67
+ * import { createCloudflareAccessAuth, getCloudflareAccessConfigFromBindings } from 'cloudflare-access/adapters/hono';
68
+ *
69
+ * const app = new Hono();
70
+ *
71
+ * app.use(createCloudflareAccessAuth({
72
+ * accessConfig: getCloudflareAccessConfigFromBindings,
73
+ * }));
74
+ *
75
+ * app.get('/protected', (c) => {
76
+ * const user = c.get('user');
77
+ * return c.json({ email: user?.email });
78
+ * });
79
+ * ```
80
+ */
81
+ declare function createCloudflareAccessAuth(options: CloudflareAccessAuthOptions): MiddlewareHandler;
82
+
83
+ export { type CloudflareAccessAuthOptions as C, type CloudflareAccessConfigResolver$1 as a, type CloudflareAccessHono as b, type CloudflareAccessVariables as c, createCloudflareAccessAuth as d, getCloudflareAccessConfigFromBindings as g, resolveConfig as r };
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Basic Example - Static Configuration
3
+ *
4
+ * This example shows the simplest usage of the middleware with
5
+ * hardcoded configuration. Not recommended for production use.
6
+ */
7
+
8
+ import { Hono } from "hono";
9
+ import { createCloudflareAccessAuth, type CloudflareAccessHono } from "cloudflare-access/hono";
10
+
11
+ // Use the helper type for proper typing
12
+ const app: CloudflareAccessHono = new Hono();
13
+
14
+ // Apply middleware with static configuration
15
+ app.use(
16
+ createCloudflareAccessAuth({
17
+ accessConfig: {
18
+ teamDomain: "https://myteam.cloudflareaccess.com",
19
+ audTag: "my-application-audience-tag",
20
+ },
21
+ }),
22
+ );
23
+
24
+ // Protected route - user is properly typed
25
+ app.get("/api/protected", (c) => {
26
+ const user = c.get("user");
27
+ return c.json({
28
+ message: "Hello from protected route",
29
+ user: {
30
+ email: user?.email,
31
+ userId: user?.userId,
32
+ },
33
+ });
34
+ });
35
+
36
+ // Health check (no auth required if excluded in config)
37
+ app.get("/health", (c) => {
38
+ return c.json({ status: "ok" });
39
+ });
40
+
41
+ export default app;
42
+
43
+ // For local testing with Bun
44
+ if (import.meta.main) {
45
+ console.log("Basic example - Static configuration");
46
+ console.log("This example requires valid Cloudflare Access credentials.");
47
+ console.log("");
48
+ console.log("To test with a real token:");
49
+ console.log(
50
+ ' curl -H "CF-Access-JWT-Assertion: <your-token>" http://localhost:8787/api/protected',
51
+ );
52
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Cloudflare Workers Example - Environment Bindings
3
+ *
4
+ * This is the recommended approach for production. Configuration is read
5
+ * from environment bindings set in wrangler.toml or Cloudflare dashboard.
6
+ */
7
+
8
+ import { Hono } from "hono";
9
+ import {
10
+ createCloudflareAccessAuth,
11
+ getCloudflareAccessConfigFromBindings,
12
+ type CloudflareAccessUser,
13
+ } from "cloudflare-access/hono";
14
+
15
+ // Define your environment bindings type
16
+ interface Bindings {
17
+ // Cloudflare Access configuration
18
+ CF_ACCESS_TEAM_DOMAIN: string;
19
+ CF_ACCESS_AUD: string;
20
+
21
+ // Your other bindings
22
+ ENVIRONMENT: string;
23
+ DB?: D1Database;
24
+ CACHE?: KVNamespace;
25
+ }
26
+
27
+ // Define variables type
28
+ interface Variables {
29
+ user?: CloudflareAccessUser;
30
+ }
31
+
32
+ const app = new Hono<{ Bindings: Bindings; Variables: Variables }>();
33
+
34
+ // Apply middleware using bindings
35
+ app.use(
36
+ createCloudflareAccessAuth({
37
+ accessConfig: getCloudflareAccessConfigFromBindings,
38
+ skipInDev: true, // Skip auth on localhost in non-prod environments
39
+ }),
40
+ );
41
+
42
+ // Protected API routes
43
+ app.get("/api/user", (c) => {
44
+ const user = c.get("user");
45
+
46
+ return c.json({
47
+ email: user?.email,
48
+ userId: user?.userId,
49
+ country: user?.country,
50
+ });
51
+ });
52
+
53
+ app.get("/api/admin", (c) => {
54
+ const user = c.get("user");
55
+
56
+ // You can access the authenticated user's email
57
+ console.log(`Admin access by: ${user?.email}`);
58
+
59
+ return c.json({
60
+ message: "Admin panel",
61
+ admin: user?.email,
62
+ });
63
+ });
64
+
65
+ // Export for Cloudflare Workers
66
+ export default app;
67
+
68
+ /*
69
+ ## wrangler.toml configuration:
70
+
71
+ name = "my-app"
72
+ main = "src/index.ts"
73
+ compatibility_date = "2024-01-01"
74
+
75
+ [vars]
76
+ ENVIRONMENT = "prod"
77
+ CF_ACCESS_TEAM_DOMAIN = "https://myteam.cloudflareaccess.com"
78
+
79
+ # Secrets (set via wrangler secret put)
80
+ # CF_ACCESS_AUD = "your-audience-tag"
81
+
82
+ ## To set secrets:
83
+ # wrangler secret put CF_ACCESS_AUD
84
+ */