create-acrylblends 0.0.0-stage → 0.1.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 (106) hide show
  1. package/bin/create-acrylblends.js +4 -0
  2. package/dist/index.d.ts +56 -0
  3. package/dist/index.js +274 -0
  4. package/dist/index.js.map +1 -0
  5. package/docs/framework/LICENSE +23 -0
  6. package/docs/framework/README.md +63 -0
  7. package/docs/framework/UPSTREAM.md +3 -0
  8. package/docs/framework/agents/index.md +24 -0
  9. package/docs/framework/api/acryl.md +259 -0
  10. package/docs/framework/api/context.md +527 -0
  11. package/docs/framework/api/exception.md +80 -0
  12. package/docs/framework/api/index.md +12 -0
  13. package/docs/framework/api/presets.md +65 -0
  14. package/docs/framework/api/request.md +396 -0
  15. package/docs/framework/api/routing.md +303 -0
  16. package/docs/framework/api/summary.md +140 -0
  17. package/docs/framework/concepts/benchmarks.md +26 -0
  18. package/docs/framework/concepts/developer-experience.md +5 -0
  19. package/docs/framework/concepts/middleware.md +21 -0
  20. package/docs/framework/concepts/motivation.md +14 -0
  21. package/docs/framework/concepts/routers.md +63 -0
  22. package/docs/framework/concepts/stacks.md +235 -0
  23. package/docs/framework/concepts/web-standard.md +37 -0
  24. package/docs/framework/cordis/acryl-in-a-cordis-app.md +146 -0
  25. package/docs/framework/cordis/concepts.md +105 -0
  26. package/docs/framework/cordis/middleware.md +8 -0
  27. package/docs/framework/cordis/migration-from-0-3.md +111 -0
  28. package/docs/framework/cordis/migration-from-0-4.md +14 -0
  29. package/docs/framework/cordis/migration-from-dsh-webserver.md +103 -0
  30. package/docs/framework/cordis/mounting.md +85 -0
  31. package/docs/framework/cordis/node-server.md +75 -0
  32. package/docs/framework/cordis/plugin-lifecycle.md +111 -0
  33. package/docs/framework/cordis/surfaces.md +71 -0
  34. package/docs/framework/cordis/transport-and-cancellation.md +57 -0
  35. package/docs/framework/cordis/validation.md +135 -0
  36. package/docs/framework/getting-started/basic.md +196 -0
  37. package/docs/framework/getting-started/bun.md +221 -0
  38. package/docs/framework/getting-started/nodejs.md +344 -0
  39. package/docs/framework/getting-started/other-runtimes.md +23 -0
  40. package/docs/framework/guides/best-practices.md +231 -0
  41. package/docs/framework/guides/create-acrylblends.md +79 -0
  42. package/docs/framework/guides/examples.md +3 -0
  43. package/docs/framework/guides/faq.md +19 -0
  44. package/docs/framework/guides/helpers.md +33 -0
  45. package/docs/framework/guides/jsx-dom.md +299 -0
  46. package/docs/framework/guides/jsx.md +440 -0
  47. package/docs/framework/guides/middleware.md +253 -0
  48. package/docs/framework/guides/rpc.md +886 -0
  49. package/docs/framework/guides/testing.md +133 -0
  50. package/docs/framework/guides/validation.md +383 -0
  51. package/docs/framework/helpers/accepts.md +60 -0
  52. package/docs/framework/helpers/adapter.md +87 -0
  53. package/docs/framework/helpers/conninfo.md +112 -0
  54. package/docs/framework/helpers/cookie.md +232 -0
  55. package/docs/framework/helpers/css.md +285 -0
  56. package/docs/framework/helpers/dev.md +67 -0
  57. package/docs/framework/helpers/factory.md +180 -0
  58. package/docs/framework/helpers/html.md +123 -0
  59. package/docs/framework/helpers/jwt.md +184 -0
  60. package/docs/framework/helpers/proxy.md +118 -0
  61. package/docs/framework/helpers/route.md +143 -0
  62. package/docs/framework/helpers/ssg.md +393 -0
  63. package/docs/framework/helpers/streaming.md +119 -0
  64. package/docs/framework/helpers/testing.md +101 -0
  65. package/docs/framework/helpers/websocket.md +215 -0
  66. package/docs/framework/middleware/builtin/basic-auth.md +165 -0
  67. package/docs/framework/middleware/builtin/bearer-auth.md +138 -0
  68. package/docs/framework/middleware/builtin/body-limit.md +71 -0
  69. package/docs/framework/middleware/builtin/cache.md +122 -0
  70. package/docs/framework/middleware/builtin/combine.md +94 -0
  71. package/docs/framework/middleware/builtin/compress.md +59 -0
  72. package/docs/framework/middleware/builtin/context-storage.md +78 -0
  73. package/docs/framework/middleware/builtin/cors.md +135 -0
  74. package/docs/framework/middleware/builtin/csrf.md +105 -0
  75. package/docs/framework/middleware/builtin/etag.md +54 -0
  76. package/docs/framework/middleware/builtin/ip-restriction.md +69 -0
  77. package/docs/framework/middleware/builtin/jsx-renderer.md +286 -0
  78. package/docs/framework/middleware/builtin/jwk.md +192 -0
  79. package/docs/framework/middleware/builtin/jwt.md +145 -0
  80. package/docs/framework/middleware/builtin/language.md +232 -0
  81. package/docs/framework/middleware/builtin/logger.md +74 -0
  82. package/docs/framework/middleware/builtin/loopback-only.md +31 -0
  83. package/docs/framework/middleware/builtin/method-not-allowed.md +48 -0
  84. package/docs/framework/middleware/builtin/method-override.md +80 -0
  85. package/docs/framework/middleware/builtin/mount.md +106 -0
  86. package/docs/framework/middleware/builtin/pretty-json.md +53 -0
  87. package/docs/framework/middleware/builtin/request-id.md +94 -0
  88. package/docs/framework/middleware/builtin/secure-headers.md +247 -0
  89. package/docs/framework/middleware/builtin/timeout.md +98 -0
  90. package/docs/framework/middleware/builtin/timing.md +101 -0
  91. package/docs/framework/middleware/builtin/trailing-slash.md +74 -0
  92. package/docs/framework/middleware/third-party.md +4 -0
  93. package/docs/framework/upstream.json +9 -0
  94. package/package.json +47 -3
  95. package/templates/bun/gitignore +1 -0
  96. package/templates/bun/package.json +19 -0
  97. package/templates/bun/src/index.ts +7 -0
  98. package/templates/bun/test/app.test.ts +8 -0
  99. package/templates/bun/tsconfig.json +15 -0
  100. package/templates/nodejs/gitignore +1 -0
  101. package/templates/nodejs/package.json +22 -0
  102. package/templates/nodejs/src/app.ts +7 -0
  103. package/templates/nodejs/src/index.ts +9 -0
  104. package/templates/nodejs/test/app.test.ts +9 -0
  105. package/templates/nodejs/tsconfig.json +16 -0
  106. package/README.md +0 -3
@@ -0,0 +1,69 @@
1
+ # IP Restriction Middleware
2
+
3
+ IP Restriction Middleware is middleware that limits access to resources based on the IP address of the user.
4
+
5
+ ## Import
6
+
7
+ ```ts
8
+ import { Acryl } from 'acrylblends'
9
+ import { ipRestriction } from 'acrylblends/ip-restriction'
10
+ ```
11
+
12
+ ## Usage
13
+
14
+ For your application running on Node.js, if you want to allow access only from local, you can write it as follows. Specify the rules you want to deny in the `denyList` and the rules you want to allow in the `allowList`.
15
+
16
+ ```ts
17
+ import { Acryl } from 'acrylblends'
18
+ import { getConnInfo } from 'acrylblends/node-server'
19
+ import { ipRestriction } from 'acrylblends/ip-restriction'
20
+
21
+ const app = new Acryl()
22
+
23
+ app.use(
24
+ '*',
25
+ ipRestriction(getConnInfo, {
26
+ denyList: [],
27
+ allowList: ['127.0.0.1', '::1'],
28
+ })
29
+ )
30
+
31
+ app.get('/', (c) => c.text('Hello Acryl!'))
32
+ ```
33
+
34
+ Pass the `getConninfo` from the [ConnInfo helper](../../helpers/conninfo.md) appropriate for your environment as the first argument of `ipRestriction`. For a runtime whose adapter is not yet available there is no `getConnInfo` to pass yet.
35
+
36
+ ## Rules
37
+
38
+ Follow the instructions below for writing rules.
39
+
40
+ ### IPv4
41
+
42
+ - `192.168.2.0` - Static IP Address
43
+ - `192.168.2.0/24` - CIDR Notation
44
+ - `*` - ALL Addresses
45
+
46
+ ### IPv6
47
+
48
+ - `::1` - Static IP Address
49
+ - `::1/10` - CIDR Notation
50
+ - `*` - ALL Addresses
51
+
52
+ ## Error handling
53
+
54
+ To customize the error, return a `Response` in the third argument.
55
+
56
+ ```ts
57
+ app.use(
58
+ '*',
59
+ ipRestriction(
60
+ getConnInfo,
61
+ {
62
+ denyList: ['192.168.2.0/24'],
63
+ },
64
+ async (remote, c) => {
65
+ return c.text(`Blocking access from ${remote.addr}`, 403)
66
+ }
67
+ )
68
+ )
69
+ ```
@@ -0,0 +1,286 @@
1
+ # JSX Renderer Middleware
2
+
3
+ > **Not yet available.** The JSX renderer middleware (`acrylblends/jsx-renderer`) is documented here so the page structure matches the rest of the framework, and is not part of acrylblends yet. The code on this page is not checked by the docs tests.
4
+
5
+
6
+ JSX Renderer Middleware allows you to set up the layout when rendering JSX with the `c.render()` function, without the need for using `c.setRenderer()`. Additionally, it enables access to instances of Context within components through the use of `useRequestContext()`.
7
+
8
+ ## Import
9
+
10
+ ```ts
11
+ import { Acryl } from 'acrylblends'
12
+ import { jsxRenderer, useRequestContext } from 'acrylblends/jsx-renderer'
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```jsx
18
+ const app = new Acryl()
19
+
20
+ app.get(
21
+ '/page/*',
22
+ jsxRenderer(({ children }) => {
23
+ return (
24
+ <html>
25
+ <body>
26
+ <header>Menu</header>
27
+ <div>{children}</div>
28
+ </body>
29
+ </html>
30
+ )
31
+ })
32
+ )
33
+
34
+ app.get('/page/about', (c) => {
35
+ return c.render(<h1>About me!</h1>)
36
+ })
37
+ ```
38
+
39
+ ## Options
40
+
41
+ ### *(optional)* docType: `boolean` | `string`
42
+
43
+ If you do not want to add a DOCTYPE at the beginning of the HTML, set the `docType` option to `false`.
44
+
45
+ ```tsx
46
+ app.use(
47
+ '*',
48
+ jsxRenderer(
49
+ ({ children }) => {
50
+ return (
51
+ <html>
52
+ <body>{children}</body>
53
+ </html>
54
+ )
55
+ },
56
+ { docType: false }
57
+ )
58
+ )
59
+ ```
60
+
61
+ And you can specify the DOCTYPE.
62
+
63
+ ```tsx
64
+ app.use(
65
+ '*',
66
+ jsxRenderer(
67
+ ({ children }) => {
68
+ return (
69
+ <html>
70
+ <body>{children}</body>
71
+ </html>
72
+ )
73
+ },
74
+ {
75
+ docType:
76
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
77
+ }
78
+ )
79
+ )
80
+ ```
81
+
82
+ ### *(optional)* stream: `boolean` | `Record<string, string>`
83
+
84
+ If you set it to `true` or provide a Record value, it will be rendered as a streaming response.
85
+
86
+ ```tsx
87
+ const AsyncComponent = async () => {
88
+ await new Promise((r) => setTimeout(r, 1000)) // sleep 1s
89
+ return <div>Hi!</div>
90
+ }
91
+
92
+ app.get(
93
+ '*',
94
+ jsxRenderer(
95
+ ({ children }) => {
96
+ return (
97
+ <html>
98
+ <body>
99
+ <h1>SSR Streaming</h1>
100
+ {children}
101
+ </body>
102
+ </html>
103
+ )
104
+ },
105
+ { stream: true }
106
+ )
107
+ )
108
+
109
+ app.get('/', (c) => {
110
+ return c.render(
111
+ <Suspense fallback={<div>loading...</div>}>
112
+ <AsyncComponent />
113
+ </Suspense>
114
+ )
115
+ })
116
+ ```
117
+
118
+ If `true` is set, the following headers are added:
119
+
120
+ ```ts
121
+ {
122
+ 'Transfer-Encoding': 'chunked',
123
+ 'Content-Type': 'text/html; charset=UTF-8',
124
+ 'Content-Encoding': 'Identity'
125
+ }
126
+ ```
127
+
128
+ You can customize the header values by specifying the Record values.
129
+
130
+ ### Function-based Options
131
+
132
+ You can pass a function that receives a `Context` object instead of a static options object. This allows you to dynamically set options based on the request context, such as environment variables or request parameters.
133
+
134
+ ```tsx
135
+ app.use(
136
+ '*',
137
+ jsxRenderer(
138
+ ({ children }) => {
139
+ return (
140
+ <html>
141
+ <body>{children}</body>
142
+ </html>
143
+ )
144
+ },
145
+ (c) => ({
146
+ stream: c.req.header('X-Enable-Streaming') === 'true',
147
+ })
148
+ )
149
+ )
150
+ ```
151
+
152
+ As a concrete example, you can use this to disable streaming when generating static sites (SSG) with `<Suspense>`, by using the [`isSSGContext`](../../helpers/ssg.md#isssgcontext) helper:
153
+
154
+ ```tsx
155
+ app.use(
156
+ '*',
157
+ jsxRenderer(
158
+ ({ children }) => {
159
+ return (
160
+ <div>
161
+ <Suspense fallback={'loading...'}>
162
+ <Component />
163
+ </Suspense>
164
+ </div>
165
+ )
166
+ },
167
+ (c) => ({
168
+ stream: !isSSGContext(c),
169
+ })
170
+ )
171
+ )
172
+ ```
173
+
174
+ ## Nested Layouts
175
+
176
+ The `Layout` component enables nesting the layouts.
177
+
178
+ ```tsx
179
+ app.use(
180
+ jsxRenderer(({ children }) => {
181
+ return (
182
+ <html>
183
+ <body>{children}</body>
184
+ </html>
185
+ )
186
+ })
187
+ )
188
+
189
+ const blog = new Acryl()
190
+ blog.use(
191
+ jsxRenderer(({ children, Layout }) => {
192
+ return (
193
+ <Layout>
194
+ <nav>Blog Menu</nav>
195
+ <div>{children}</div>
196
+ </Layout>
197
+ )
198
+ })
199
+ )
200
+
201
+ app.route('/blog', blog)
202
+ ```
203
+
204
+ ## `useRequestContext()`
205
+
206
+ `useRequestContext()` returns an instance of Context.
207
+
208
+ ```tsx
209
+ import { useRequestContext, jsxRenderer } from 'acrylblends/jsx-renderer'
210
+
211
+ const app = new Acryl()
212
+ app.use(jsxRenderer())
213
+
214
+ const RequestUrlBadge: FC = () => {
215
+ const c = useRequestContext()
216
+ return <b>{c.req.url}</b>
217
+ }
218
+
219
+ app.get('/page/info', (c) => {
220
+ return c.render(
221
+ <div>
222
+ You are accessing: <RequestUrlBadge />
223
+ </div>
224
+ )
225
+ })
226
+ ```
227
+
228
+ **Warning.**
229
+
230
+ You can't use `useRequestContext()` with the Deno's `precompile` JSX option. Use the `react-jsx`:
231
+
232
+ ```json
233
+ "compilerOptions": {
234
+ "jsx": "react-jsx",
235
+ "jsxImportSource": "acrylblends/jsx"
236
+ }
237
+ }
238
+ ```
239
+
240
+ ## Extending `ContextRenderer`
241
+
242
+ By defining `ContextRenderer` as shown below, you can pass additional content to the renderer. This is handy, for instance, when you want to change the contents of the head tag depending on the page.
243
+
244
+ ```tsx
245
+ declare module 'acrylblends' {
246
+ interface ContextRenderer {
247
+ (
248
+ content: string | Promise<string>,
249
+ props: { title: string }
250
+ ): Response
251
+ }
252
+ }
253
+
254
+ const app = new Acryl()
255
+
256
+ app.get(
257
+ '/page/*',
258
+ jsxRenderer(({ children, title }) => {
259
+ return (
260
+ <html>
261
+ <head>
262
+ <title>{title}</title>
263
+ </head>
264
+ <body>
265
+ <header>Menu</header>
266
+ <div>{children}</div>
267
+ </body>
268
+ </html>
269
+ )
270
+ })
271
+ )
272
+
273
+ app.get('/page/favorites', (c) => {
274
+ return c.render(
275
+ <div>
276
+ <ul>
277
+ <li>Eating sushi</li>
278
+ <li>Watching baseball games</li>
279
+ </ul>
280
+ </div>,
281
+ {
282
+ title: 'My favorites',
283
+ }
284
+ )
285
+ })
286
+ ```
@@ -0,0 +1,192 @@
1
+ # JWK Auth Middleware
2
+
3
+ The JWK Auth Middleware authenticates requests by verifying tokens using JWK (JSON Web Key). It checks for an `Authorization` header and other configured sources, such as cookies, if specified. It validates tokens using the provided `keys`, retrieves keys from `jwks_uri` if specified, and supports token extraction from cookies if the `cookie` option is set.
4
+
5
+ ## What this middleware validates
6
+
7
+ For each token, `jwk()`:
8
+
9
+ - Parses and validates the JWT header format.
10
+ - Requires a `kid` header and finds a matching key by `kid`.
11
+ - Rejects symmetric algorithms (`HS256`, `HS384`, `HS512`).
12
+ - Requires the header `alg` to be included in the configured `alg` allowlist.
13
+ - If a matched JWK has an `alg` field, requires it to match the JWT header `alg`.
14
+ - Verifies the token signature with the matched key.
15
+ - By default, validates time-based claims: `nbf`, `exp`, and `iat`.
16
+
17
+ Optional claim validation can be configured with the `verification` option:
18
+
19
+ - `iss`: validates issuer when provided.
20
+ - `aud`: validates audience when provided.
21
+
22
+ If you need additional token checks beyond the above (for example, custom application-level authorization rules), add them in your own middleware after `jwk()`.
23
+
24
+ > **Note.** The Authorization header sent from the client must have a specified scheme.
25
+ >
26
+ > Example: `Bearer my.token.value` or `Basic my.token.value`
27
+
28
+ ## Import
29
+
30
+ ```ts
31
+ import { Acryl } from 'acrylblends'
32
+ import { jwk } from 'acrylblends/jwk'
33
+ import { verifyWithJwks } from 'acrylblends/jwt'
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ```ts
39
+ const app = new Acryl()
40
+
41
+ app.use(
42
+ '/auth/*',
43
+ jwk({
44
+ jwks_uri: `https://${backendServer}/.well-known/jwks.json`,
45
+ alg: ['RS256'],
46
+ })
47
+ )
48
+
49
+ app.get('/auth/page', (c) => {
50
+ return c.text('You are authorized')
51
+ })
52
+ ```
53
+
54
+ Get payload:
55
+
56
+ ```ts
57
+ const app = new Acryl()
58
+
59
+ app.use(
60
+ '/auth/*',
61
+ jwk({
62
+ jwks_uri: `https://${backendServer}/.well-known/jwks.json`,
63
+ alg: ['RS256'],
64
+ })
65
+ )
66
+
67
+ app.get('/auth/page', (c) => {
68
+ const payload = c.get('jwtPayload')
69
+ return c.json(payload) // eg: { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
70
+ })
71
+ ```
72
+
73
+ Anonymous access:
74
+
75
+ ```ts
76
+ const app = new Acryl()
77
+
78
+ app.use(
79
+ '/auth/*',
80
+ jwk({
81
+ jwks_uri: (c) =>
82
+ `https://${c.env.authServer}/.well-known/jwks.json`,
83
+ alg: ['RS256'],
84
+ allow_anon: true,
85
+ })
86
+ )
87
+
88
+ app.get('/auth/page', (c) => {
89
+ const payload = c.get('jwtPayload')
90
+ return c.json(payload ?? { message: 'hello anon' })
91
+ })
92
+ ```
93
+
94
+ ## Using `verifyWithJwks` outside of middleware
95
+
96
+ The `verifyWithJwks` utility function can be used to verify JWT tokens outside of Acryl's middleware context, such as in SvelteKit SSR pages or other server-side environments:
97
+
98
+ ```ts
99
+ const id_payload = await verifyWithJwks(
100
+ id_token,
101
+ {
102
+ jwks_uri: 'https://your-auth-server/.well-known/jwks.json',
103
+ allowedAlgorithms: ['RS256'],
104
+ },
105
+ {
106
+ cf: { cacheEverything: true, cacheTtl: 3600 },
107
+ }
108
+ )
109
+ ```
110
+
111
+ ## Configuring JWKS fetch request options
112
+
113
+ To configure how JWKS is retrieved from `jwks_uri`, pass fetch request options as the second argument of `jwk()`.
114
+
115
+ This argument is `RequestInit` and is used only for the JWKS fetch request.
116
+
117
+ ```ts
118
+ const app = new Acryl()
119
+
120
+ app.use(
121
+ '/auth/*',
122
+ jwk(
123
+ {
124
+ jwks_uri: `https://${backendServer}/.well-known/jwks.json`,
125
+ alg: ['RS256'],
126
+ },
127
+ {
128
+ headers: {
129
+ Authorization: 'Bearer TOKEN',
130
+ },
131
+ }
132
+ )
133
+ )
134
+ ```
135
+
136
+ ## Options
137
+
138
+ ### **(required)** alg: `AsymmetricAlgorithm[]`
139
+
140
+ An array of allowed asymmetric algorithms used for token verification.
141
+
142
+ Available types are `RS256` | `RS384` | `RS512` | `PS256` | `PS384` | `PS512` | `ES256` | `ES384` | `ES512` | `EdDSA`.
143
+
144
+ ### *(optional)* keys: `AcrylJsonWebKey[] | (c: Context) => Promise<AcrylJsonWebKey[]>`
145
+
146
+ The values of your public keys, or a function that returns them. The function receives the Context object.
147
+
148
+ ### *(optional)* jwks_uri: `string` | `(c: Context) => Promise<string>`
149
+
150
+ If this value is set, attempt to fetch JWKs from this URI, expecting a JSON response with `keys`, which are added to the provided `keys` option. You can also pass a callback function to dynamically determine the JWKS URI using the Context.
151
+
152
+ ### *(optional)* allow_anon: `boolean`
153
+
154
+ If this value is set to `true`, requests without a valid token will be allowed to pass through the middleware. Use `c.get('jwtPayload')` to check if the request is authenticated. The default is `false`.
155
+
156
+ ### *(optional)* cookie: `string`
157
+
158
+ If this value is set, then the value is retrieved from the cookie header using that value as a key, which is then validated as a token.
159
+
160
+ ### *(optional)* headerName: `string`
161
+
162
+ The name of the header to look for the JWT token. The default is `Authorization`.
163
+
164
+ ### *(optional)* realm: `string`
165
+
166
+ The protection space described by the `realm` parameter of the `WWW-Authenticate` challenge header returned on `401` responses. The default is the request URL.
167
+
168
+ ### *(optional)* verification: `VerifyOptions`
169
+
170
+ Configure claim validation behavior in addition to signature verification:
171
+
172
+ [Keep in sync with jwt.md]: #
173
+
174
+ #### *(optional)* VerifyOptions.iss: `string | RegExp`
175
+
176
+ The expected issuer used for token verification. The `iss` claim will **not** be checked if this isn't set.
177
+
178
+ #### *(optional)* VerifyOptions.aud: `string | string[] | RegExp`
179
+
180
+ The expected audience used for token verification. If this is set, the token must include an `aud` claim and at least one audience value must match.
181
+
182
+ #### *(optional)* VerifyOptions.nbf: `boolean`
183
+
184
+ The `nbf` (not before) claim will be verified if present and this is set to `true`. The default is `true`.
185
+
186
+ #### *(optional)* VerifyOptions.iat: `boolean`
187
+
188
+ The `iat` (issued at) claim will be verified if present and this is set to `true`. The default is `true`.
189
+
190
+ #### *(optional)* VerifyOptions.exp: `boolean`
191
+
192
+ The `exp` (expiration time) claim will be verified if present and this is set to `true`. The default is `true`.
@@ -0,0 +1,145 @@
1
+ # JWT Auth Middleware
2
+
3
+ The JWT Auth Middleware provides authentication by verifying the token with JWT.
4
+ The middleware will check for an `Authorization` header if the `cookie` option is not set. You can customize the header name using the `headerName` option.
5
+
6
+ > **Note.** The Authorization header sent from the client must have a specified scheme.
7
+ >
8
+ > Example: `Bearer my.token.value` or `Basic my.token.value`
9
+
10
+ ## Import
11
+
12
+ ```ts
13
+ import { Acryl } from 'acrylblends'
14
+ import { jwt } from 'acrylblends/jwt'
15
+ import type { JwtVariables } from 'acrylblends/jwt'
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```ts
21
+ // Specify the variable types to infer the `c.get('jwtPayload')`:
22
+ type Variables = JwtVariables
23
+
24
+ const app = new Acryl<{ Variables: Variables }>()
25
+
26
+ app.use(
27
+ '/auth/*',
28
+ jwt({
29
+ secret: process.env.JWT_SECRET!,
30
+ alg: 'HS256',
31
+ })
32
+ )
33
+
34
+ app.get('/auth/page', (c) => {
35
+ return c.text('You are authorized')
36
+ })
37
+ ```
38
+
39
+ Get payload:
40
+
41
+ ```ts
42
+ const app = new Acryl()
43
+
44
+ app.use(
45
+ '/auth/*',
46
+ jwt({
47
+ secret: process.env.JWT_SECRET!,
48
+ alg: 'HS256',
49
+ verification: {
50
+ iss: 'my-trusted-issuer',
51
+ aud: 'my-api',
52
+ },
53
+ })
54
+ )
55
+
56
+ app.get('/auth/page', (c) => {
57
+ const payload = c.get('jwtPayload')
58
+ return c.json(payload) // eg: { "sub": "1234567890", "name": "John Doe", "iat": 1516239022, "iss": "my-trusted-issuer" }
59
+ })
60
+ ```
61
+
62
+ **Tip.**
63
+
64
+ `jwt()` is just a middleware function. If you want to use an environment variable (eg: `c.env.JWT_SECRET`), you can use it as follows:
65
+
66
+ ```js
67
+ app.use('/auth/*', (c, next) => {
68
+ const jwtMiddleware = jwt({
69
+ secret: c.env.JWT_SECRET,
70
+ alg: 'HS256',
71
+ })
72
+ return jwtMiddleware(c, next)
73
+ })
74
+ ```
75
+
76
+ ## Options
77
+
78
+ ### **(required)** secret: `string`
79
+
80
+ A value of your secret key.
81
+
82
+ ### **(required)** alg: `string`
83
+
84
+ An algorithm type that is used for verifying.
85
+
86
+ Available types are `HS256` | `HS384` | `HS512` | `RS256` | `RS384` | `RS512` | `PS256` | `PS384` | `PS512` | `ES256` | `ES384` | `ES512` | `EdDSA`.
87
+
88
+ ### *(optional)* cookie: `string`
89
+
90
+ If this value is set, then the value is retrieved from the cookie header using that value as a key, which is then validated as a token.
91
+
92
+ ### *(optional)* headerName: `string`
93
+
94
+ The name of the header to look for the JWT token. The default is `Authorization`.
95
+
96
+ ```ts
97
+ app.use(
98
+ '/auth/*',
99
+ jwt({
100
+ secret: process.env.JWT_SECRET!,
101
+ alg: 'HS256',
102
+ headerName: 'x-custom-auth-header',
103
+ })
104
+ )
105
+ ```
106
+
107
+ ### *(optional)* realm: `string`
108
+
109
+ The protection space described by the `realm` parameter of the `WWW-Authenticate` challenge header returned on `401` responses. The default is the request URL.
110
+
111
+ ```ts
112
+ app.use(
113
+ '/auth/*',
114
+ jwt({
115
+ secret: process.env.JWT_SECRET!,
116
+ realm: 'my-protected-api',
117
+ })
118
+ )
119
+ ```
120
+
121
+ ### *(optional)* verification: `VerifyOptions`
122
+
123
+ Options controlling verification of the token.
124
+
125
+ [Keep in sync with jwk.md]: #
126
+
127
+ #### *(optional)* VerifyOptions.iss: `string | RegExp`
128
+
129
+ The expected issuer used for token verification. The `iss` claim will **not** be checked if this isn't set.
130
+
131
+ #### *(optional)* VerifyOptions.aud: `string | string[] | RegExp`
132
+
133
+ The expected audience used for token verification. If this is set, the token must include an `aud` claim and at least one audience value must match.
134
+
135
+ #### *(optional)* VerifyOptions.nbf: `boolean`
136
+
137
+ The `nbf` (not before) claim will be verified if present and this is set to `true`. The default is `true`.
138
+
139
+ #### *(optional)* VerifyOptions.iat: `boolean`
140
+
141
+ The `iat` (issued at) claim will be verified if present and this is set to `true`. The default is `true`.
142
+
143
+ #### *(optional)* VerifyOptions.exp: `boolean`
144
+
145
+ The `exp` (expiration time) claim will be verified if present and this is set to `true`. The default is `true`.