@tidecloak/create-nextjs 0.14.33-staging → 0.14.33
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/README.md +63 -48
- package/dist/cjs/create.cjs +6 -1
- package/dist/cjs/create.js.map +1 -1
- package/dist/esm/create.js +6 -1
- package/dist/esm/create.js.map +1 -1
- package/init/tcinit.sh +2 -2
- package/package.json +2 -1
- package/template-js-app/app/api/protected/route.js +2 -0
- package/template-js-app/app/home/page.jsx +3 -3
- package/template-js-app/app/protected/page.jsx +8 -0
- package/template-js-app/app/tide_dpop/[...path]/route.js +8 -9
- package/template-js-app/init/.env.example +1 -0
- package/template-js-app/init/tcinit.sh +4 -3
- package/template-js-app/package.json +2 -2
- package/template-js-app/{middleware.js → proxy.js} +35 -35
- package/template-ts-app/app/api/protected/route.ts +2 -0
- package/template-ts-app/app/home/page.tsx +3 -3
- package/template-ts-app/app/protected/page.tsx +8 -0
- package/template-ts-app/app/tide_dpop/[...path]/route.ts +8 -9
- package/template-ts-app/init/.env.example +1 -0
- package/template-ts-app/init/tcinit.sh +4 -3
- package/template-ts-app/package.json +2 -2
- package/template-ts-app/{middleware.ts → proxy.ts} +7 -7
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Jump to:
|
|
|
8
8
|
---
|
|
9
9
|
# Quickstart
|
|
10
10
|
|
|
11
|
-
Secure your Next.js app with TideCloak: authentication, session management, data encryption, and
|
|
11
|
+
Secure your Next.js app with TideCloak: authentication, session management, data encryption, and server-side route protection, all in minutes.
|
|
12
12
|
|
|
13
13
|
[](https://www.youtube.com/watch?v=dVpDUF_XJdw "Provably secure your Next.js apps in 5 mins, with TideCloak")
|
|
14
14
|
|
|
@@ -18,10 +18,9 @@ Before you begin, ensure you have:
|
|
|
18
18
|
|
|
19
19
|
* A [running](https://github.com/tide-foundation/tidecloak-gettingstarted) TideCloak server you have admin control over. No need to set anything up - just start the server.
|
|
20
20
|
|
|
21
|
-
As well as
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* Node.js ≥18.17.0
|
|
21
|
+
As well as
|
|
22
|
+
* Node.js 20.9 or later (the template is a Next.js 16 app with React 19)
|
|
23
|
+
* `curl` and `jq`, if you let the scaffolder initialize TideCloak for you
|
|
25
24
|
|
|
26
25
|
|
|
27
26
|
### 2. Initialize the template project
|
|
@@ -36,27 +35,43 @@ npm init @tidecloak/nextjs@latest my-app
|
|
|
36
35
|
|
|
37
36
|
#### 2.a Project structure
|
|
38
37
|
|
|
38
|
+
The JavaScript template is shown. The TypeScript one has the same layout with `.ts`/`.tsx` files and a `tsconfig.json`, and puts the provider straight into `app/layout.tsx`.
|
|
39
|
+
|
|
39
40
|
```
|
|
40
41
|
my-app/
|
|
41
42
|
├── app/
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
43
|
+
│ ├── api/
|
|
44
|
+
│ │ └── protected/
|
|
45
|
+
│ │ └── route.js <- A protected API route that verifies the user's access token
|
|
46
|
+
│ ├── auth/
|
|
47
|
+
│ │ └── redirect/
|
|
48
|
+
│ │ └── page.jsx <- Where the user lands once authentication is complete
|
|
49
|
+
│ ├── home/
|
|
50
|
+
│ │ └── page.jsx <- Home page for authenticated users (includes an encrypted note)
|
|
51
|
+
│ ├── protected/
|
|
52
|
+
│ │ └── page.jsx <- Example page guarded server-side by proxy.js
|
|
53
|
+
│ ├── tide_dpop/
|
|
54
|
+
│ │ └── [...path]/
|
|
55
|
+
│ │ └── route.js <- Serves tide_dpop_auth.html, only needed if you turn on useDPoP
|
|
56
|
+
│ ├── layout.jsx <- Root layout
|
|
57
|
+
│ ├── page.jsx <- Login page
|
|
58
|
+
│ └── provider.jsx <- Wraps the app in TideCloakProvider
|
|
59
|
+
├── init/
|
|
60
|
+
│ ├── .env.example <- Defaults for tcinit.sh
|
|
61
|
+
│ ├── realm.json <- Realm template used by tcinit.sh
|
|
62
|
+
│ └── tcinit.sh <- Provisions the realm and writes tidecloak.json (npm run init)
|
|
52
63
|
├── public/
|
|
53
|
-
│
|
|
54
|
-
|
|
64
|
+
│ ├── silent-check-sso.html <- Silent SSO check page
|
|
65
|
+
│ └── tide_dpop_auth.html <- DPoP helper page (only used with useDPoP)
|
|
66
|
+
├── tidecloak.json <- Your TideCloak adapter config (a {} placeholder until init runs)
|
|
67
|
+
├── proxy.js <- Verifies the token server-side before protected pages load
|
|
68
|
+
├── jsconfig.json
|
|
55
69
|
├── next.config.js
|
|
56
|
-
├── middleware.js <- Run on each page navigation - this is where the Tidecloak token is verified
|
|
57
70
|
└── package.json
|
|
58
71
|
```
|
|
59
72
|
|
|
73
|
+
If you skipped initialization, run `npm run init` inside the app later. It writes `tidecloak.json` to the app root; set `ADAPTER_OUTPUT_PATH` to write it somewhere else.
|
|
74
|
+
|
|
60
75
|
### 3. Test your app!
|
|
61
76
|
|
|
62
77
|
```npm run dev```
|
|
@@ -69,12 +84,7 @@ Here it is - [localhost:3000](http://localhost:3000)
|
|
|
69
84
|
|
|
70
85
|
|
|
71
86
|
### Implementing encryption/decryption
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
> [!NOTE]
|
|
75
|
-
> You have already completed the pre-requisites asked for in the documentation to set up encrypt/decrypt roles AND also set up the required client.
|
|
76
|
-
|
|
77
|
-
[Set up encrypt/decrypt roles](https://docs.tidecloak.com/docs/EncryptDecrypt/SetupED)
|
|
87
|
+
The realm created by init already gives every user the `_tide_message.selfencrypt` and `_tide_message.selfdecrypt` roles, which the home page uses for its encrypted note. To encrypt data under other tags, [set up matching roles](https://docs.tidecloak.com/docs/EncryptDecrypt/SetupED).
|
|
78
88
|
|
|
79
89
|
TideCloak lets you protect sensitive fields with **tag-based** encryption. Pass in an array of `{ data, tags }` objects and receive encrypted strings (or vice versa).
|
|
80
90
|
|
|
@@ -109,7 +119,8 @@ This bundle provides:
|
|
|
109
119
|
* `verifyTideCloakToken()` - server-side JWT verification
|
|
110
120
|
* `<Authenticated>` / `<Unauthenticated>` - UI guards
|
|
111
121
|
* `doEncrypt()` / `doDecrypt()` - tag-based encryption/decryption
|
|
112
|
-
* `
|
|
122
|
+
* `createTideCloakProxy()` - route protection in `proxy.ts` (Next.js 16+, used by the template)
|
|
123
|
+
* `createTideCloakMiddleware()` - route protection in `middleware.ts` (Next.js 13.5 to 15)
|
|
113
124
|
|
|
114
125
|
|
|
115
126
|
### Using the `useTideCloak` Hook
|
|
@@ -159,13 +170,13 @@ function Header() {
|
|
|
159
170
|
| `authenticated` | `boolean` | Whether the user is logged in. |
|
|
160
171
|
| `login()` / `logout()` | `() => void` | Trigger the login or logout flows. |
|
|
161
172
|
| `token`, `tokenExp` | `string`, `number` | Access token and its expiration timestamp. |
|
|
162
|
-
| Automatic token refresh | built-in | Tokens refresh silently on expiration
|
|
173
|
+
| Automatic token refresh | built-in | Tokens refresh silently on expiration, no manual setup needed. |
|
|
163
174
|
| `refreshToken()` | `() => Promise<boolean>` | Force a silent token renewal. |
|
|
164
175
|
| `getValueFromToken(key)` | `(key: string) => any` | Read a custom claim from the access token. |
|
|
165
176
|
| `getValueFromIdToken(key)` | `(key: string) => any` | Read a custom claim from the ID token. |
|
|
166
177
|
| `hasRealmRole(role)` | `(role: string) => boolean` | Check a realm-level role. |
|
|
167
178
|
| `hasClientRole(role, client?)` | `(role: string, client?: string) => boolean` | Check a client-level role; defaults to your app’s client ID if omitted. |
|
|
168
|
-
| `doEncrypt(data)` / `doDecrypt(data)` | `(data: any) => Promise<any>`
|
|
179
|
+
| `doEncrypt(data, policy?)` / `doDecrypt(data, policy?)` | `(data: any, policy?: Uint8Array) => Promise<any>` | Encrypt or decrypt payloads, optionally under a signed decryption policy. |
|
|
169
180
|
|
|
170
181
|
|
|
171
182
|
### Guard Components
|
|
@@ -202,21 +213,21 @@ TideCloak provides server-side route protection for both the **Pages Router** an
|
|
|
202
213
|
|
|
203
214
|
#### Options
|
|
204
215
|
|
|
205
|
-
* **`config`** (`TidecloakConfig`):
|
|
216
|
+
* **`config`** (`TidecloakConfig`): The contents of your `tidecloak.json` adapter config.
|
|
206
217
|
* **`protectedRoutes`** (`ProtectedRoutesMap`): Map of path patterns to arrays of required roles. A trailing `/*` glob (e.g. `"/admin/*"`) also matches the bare base path (`/admin`).
|
|
207
218
|
* **`cookieName`** (`string`, default `"kcToken"`): Name of the cookie that holds the access token.
|
|
208
219
|
* **`onRequest`**<br>`(ctx: { token: string | null }, req: NextRequest) => NextResponse | void`<br>Hook before auth logic; can short-circuit by returning a `NextResponse`.
|
|
209
220
|
* **`onSuccess`**<br>`(ctx: { payload: Record<string, any> }, req: NextRequest) => NextResponse | void`<br>Hook after successful auth & role checks; override the response by returning one.
|
|
210
221
|
* **`onFailure`**<br>`(ctx: { token: string | null }, req: NextRequest) => NextResponse | void`<br>Hook when auth or role check fails; return a `NextResponse` to override.
|
|
211
|
-
* **`onError`**<br>`(err: any, req: NextRequest) => NextResponse`<br>Hook for unexpected errors
|
|
222
|
+
* **`onError`**<br>`(err: any, req: NextRequest) => NextResponse`<br>Hook for unexpected errors during verification.
|
|
212
223
|
|
|
213
224
|
#### Next.js 16+ (proxy.ts)
|
|
214
225
|
|
|
215
|
-
Create `proxy.ts` at your project root. Proxy runs on Node.js runtime.
|
|
226
|
+
Create `proxy.ts` at your project root. Proxy runs on the Node.js runtime.
|
|
216
227
|
|
|
217
228
|
```ts
|
|
218
229
|
import { NextResponse } from 'next/server';
|
|
219
|
-
import tidecloakConfig from './
|
|
230
|
+
import tidecloakConfig from './tidecloak.json';
|
|
220
231
|
import { createTideCloakProxy } from '@tidecloak/nextjs/server';
|
|
221
232
|
|
|
222
233
|
export const proxy = createTideCloakProxy({
|
|
@@ -228,17 +239,22 @@ export const proxy = createTideCloakProxy({
|
|
|
228
239
|
onFailure: ({ token }, req) => NextResponse.redirect(new URL('/login', req.url)),
|
|
229
240
|
onError: (err, req) => NextResponse.rewrite(new URL('/error', req.url)),
|
|
230
241
|
});
|
|
242
|
+
|
|
243
|
+
// Optional: limit which paths run the proxy
|
|
244
|
+
export const config = {
|
|
245
|
+
matcher: ['/admin/:path*', '/api/private/:path*'],
|
|
246
|
+
};
|
|
231
247
|
```
|
|
232
248
|
|
|
233
|
-
>
|
|
249
|
+
> `export const config = { matcher }` works in `proxy.ts`. Don't set `runtime` there: proxy always runs on the Node.js runtime.
|
|
234
250
|
|
|
235
|
-
#### Next.js 13
|
|
251
|
+
#### Next.js 13.5 to 15 (middleware.ts)
|
|
236
252
|
|
|
237
253
|
Create `middleware.ts` at your project root. Middleware runs on Edge runtime.
|
|
238
254
|
|
|
239
255
|
```ts
|
|
240
256
|
import { NextResponse } from 'next/server';
|
|
241
|
-
import tidecloakConfig from './
|
|
257
|
+
import tidecloakConfig from './tidecloak.json';
|
|
242
258
|
import { createTideCloakMiddleware } from '@tidecloak/nextjs/server';
|
|
243
259
|
|
|
244
260
|
export default createTideCloakMiddleware({
|
|
@@ -261,14 +277,13 @@ export const config = {
|
|
|
261
277
|
|
|
262
278
|
**Flow:**
|
|
263
279
|
|
|
264
|
-
1.
|
|
265
|
-
2.
|
|
266
|
-
3.
|
|
267
|
-
4.
|
|
268
|
-
5.
|
|
269
|
-
6. On
|
|
270
|
-
7. On
|
|
271
|
-
8. On unexpected errors: `onError` hook
|
|
280
|
+
1. Read the `kcToken` cookie
|
|
281
|
+
2. Invoke `onRequest` hook (if provided)
|
|
282
|
+
3. Match path against `protectedRoutes` patterns
|
|
283
|
+
4. Verify signature, issuer, and roles via `verifyTideCloakToken()`
|
|
284
|
+
5. On success: `onSuccess` hook or `NextResponse.next()`
|
|
285
|
+
6. On failure: `onFailure` hook or default 403 response
|
|
286
|
+
7. On unexpected errors: `onError` hook
|
|
272
287
|
|
|
273
288
|
|
|
274
289
|
#### Server‑Side Token Verification
|
|
@@ -280,7 +295,7 @@ import { verifyTideCloakToken } from '@tidecloak/nextjs/server';
|
|
|
280
295
|
|
|
281
296
|
// Returns the decoded payload if valid and roles pass, otherwise null
|
|
282
297
|
const payload = await verifyTideCloakToken(
|
|
283
|
-
config, // Your
|
|
298
|
+
config, // Your tidecloak.json contents
|
|
284
299
|
token, // Raw access token to verify
|
|
285
300
|
['admin', 'user'] // Optional roles; user must have at least one
|
|
286
301
|
);
|
|
@@ -303,13 +318,13 @@ export async function verifyTideCloakToken(config, token, allowedRoles = []) {
|
|
|
303
318
|
|
|
304
319
|
**Parameters:**
|
|
305
320
|
|
|
306
|
-
* `config` (`object`): Your
|
|
321
|
+
* `config` (`object`): Your parsed `tidecloak.json` adapter config.
|
|
307
322
|
* `token` (`string`): Access token string to verify.
|
|
308
323
|
* `allowedRoles` (`string[]`, optional): Array of realm or client roles; user must have at least one.
|
|
309
324
|
|
|
310
325
|
**Returns:**
|
|
311
326
|
|
|
312
|
-
* `Promise<
|
|
327
|
+
* `Promise<TideTokenClaims | null>`: Decoded token claims if valid and the role check passes; otherwise `null`.
|
|
313
328
|
|
|
314
329
|
#### Example: Protecting an API Route
|
|
315
330
|
|
|
@@ -321,7 +336,7 @@ Protect your server-side endpoints by verifying the JWT before proceeding.
|
|
|
321
336
|
// pages/api/secure.ts
|
|
322
337
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
|
323
338
|
import { verifyTideCloakToken } from '@tidecloak/nextjs/server';
|
|
324
|
-
import config from '../../
|
|
339
|
+
import config from '../../tidecloak.json';
|
|
325
340
|
|
|
326
341
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|
327
342
|
// Extract token from cookie or Authorization header
|
|
@@ -344,7 +359,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|
|
344
359
|
// app/api/secure/route.ts
|
|
345
360
|
import { NextRequest, NextResponse } from 'next/server';
|
|
346
361
|
import { verifyTideCloakToken } from '@tidecloak/nextjs/server';
|
|
347
|
-
import config from '../../../
|
|
362
|
+
import config from '../../../tidecloak.json';
|
|
348
363
|
|
|
349
364
|
export async function GET(req: NextRequest) {
|
|
350
365
|
// Extract token from cookie
|
|
@@ -363,7 +378,7 @@ export async function GET(req: NextRequest) {
|
|
|
363
378
|
|
|
364
379
|
### Advanced & Best Practices
|
|
365
380
|
|
|
366
|
-
* **Auto-Refresh**: built into the provider
|
|
381
|
+
* **Auto-Refresh**: built into the provider, no manual timers.
|
|
367
382
|
* **Error Handling**: use the `initError` value from `useTideCloak`.
|
|
368
383
|
* **Custom Claims**: read via `getValueFromToken()` / `getValueFromIdToken()`.
|
|
369
384
|
* **Role-Based UI**: combine hooks & guard components for fine-grained control.
|
package/dist/cjs/create.cjs
CHANGED
|
@@ -37,7 +37,12 @@ async function main() {
|
|
|
37
37
|
? 'template-ts-app'
|
|
38
38
|
: 'template-js-app';
|
|
39
39
|
const templateDir = path_1.default.resolve(packageRoot, templateName);
|
|
40
|
-
|
|
40
|
+
// Skip local build output and installs that may exist in a dev checkout of the template.
|
|
41
|
+
const skipped = new Set(['.next', 'node_modules', 'package-lock.json']);
|
|
42
|
+
fs_1.default.cpSync(templateDir, targetDir, {
|
|
43
|
+
recursive: true,
|
|
44
|
+
filter: (src) => !skipped.has(path_1.default.basename(src)),
|
|
45
|
+
});
|
|
41
46
|
console.log(`Scaffolded ${language} template into "${targetDir}"`);
|
|
42
47
|
// 3. Prompt for initialization
|
|
43
48
|
const { initialize } = await prompt({
|
package/dist/cjs/create.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../create.ts"],"names":[],"mappings":";;;;;;AACA,4CAAmB;AACnB,gDAAuB;AACvB,iDAAwC;AACxC,wDAA+B;AAE/B,MAAM,EAAE,MAAM,EAAE,GAAG,kBAAQ,CAAA;AAE3B,SAAS,UAAU,CAAC,GAAW;IAC7B,IAAI,CAAC;QACH,IAAA,wBAAQ,EAAC,cAAc,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;QAClD,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,CAAC,EAAE,AAAD,EAAG,SAAS,CAAC,GAAG,OAAO,CAAC,IAAgB,CAAA;IAChD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAA;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,qBAAqB;IACrB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAA4C;QAC3E,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,yBAAyB;QAClC,OAAO,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;KACtC,CAAC,CAAA;IAEF,uBAAuB;IACvB,MAAM,WAAW,GAAG,cAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;IACvD,MAAM,YAAY,GAAG,QAAQ,KAAK,YAAY;QAC5C,CAAC,CAAC,iBAAiB;QACnB,CAAC,CAAC,iBAAiB,CAAA;IACrB,MAAM,WAAW,GAAG,cAAI,CAAC,OAAO,CAAC,WAAW,EAAE,YAAY,CAAC,CAAA;IAC3D,YAAE,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../create.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/create.js
CHANGED
|
@@ -32,7 +32,12 @@ async function main() {
|
|
|
32
32
|
? 'template-ts-app'
|
|
33
33
|
: 'template-js-app';
|
|
34
34
|
const templateDir = path.resolve(packageRoot, templateName);
|
|
35
|
-
|
|
35
|
+
// Skip local build output and installs that may exist in a dev checkout of the template.
|
|
36
|
+
const skipped = new Set(['.next', 'node_modules', 'package-lock.json']);
|
|
37
|
+
fs.cpSync(templateDir, targetDir, {
|
|
38
|
+
recursive: true,
|
|
39
|
+
filter: (src) => !skipped.has(path.basename(src)),
|
|
40
|
+
});
|
|
36
41
|
console.log(`Scaffolded ${language} template into "${targetDir}"`);
|
|
37
42
|
// 3. Prompt for initialization
|
|
38
43
|
const { initialize } = await prompt({
|
package/dist/esm/create.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../create.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,QAAQ,MAAM,UAAU,CAAA;AAE/B,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAA;AAE3B,SAAS,UAAU,CAAC,GAAW;IAC7B,IAAI,CAAC;QACH,QAAQ,CAAC,cAAc,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;QAClD,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,CAAC,EAAE,AAAD,EAAG,SAAS,CAAC,GAAG,OAAO,CAAC,IAAgB,CAAA;IAChD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAA;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,qBAAqB;IACrB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAA4C;QAC3E,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,yBAAyB;QAClC,OAAO,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;KACtC,CAAC,CAAA;IAEF,uBAAuB;IACvB,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;IACvD,MAAM,YAAY,GAAG,QAAQ,KAAK,YAAY;QAC5C,CAAC,CAAC,iBAAiB;QACnB,CAAC,CAAC,iBAAiB,CAAA;IACrB,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,YAAY,CAAC,CAAA;IAC3D,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../create.ts"],"names":[],"mappings":"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"}
|
package/init/tcinit.sh
CHANGED
|
@@ -17,8 +17,8 @@ set -euo pipefail
|
|
|
17
17
|
#
|
|
18
18
|
# The governance body below (from "Helper: grab a fresh master admin-cli
|
|
19
19
|
# token" onward) is IDENTICAL to the two shipped template copies under
|
|
20
|
-
# template-ts-app/init/ and template-js-app/init
|
|
21
|
-
#
|
|
20
|
+
# template-ts-app/init/ and template-js-app/init/, and test/tcinit-sync.test.mjs
|
|
21
|
+
# fails if they drift. Only this path/bootstrap preamble differs.
|
|
22
22
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
23
23
|
|
|
24
24
|
# ─── Determine paths ─────────────────────────────────────────────────────────
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tidecloak/create-nextjs",
|
|
3
|
-
"version": "0.14.33
|
|
3
|
+
"version": "0.14.33",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Scaffold a TideCloak-ready Next.js app with optional IAM setup and working auth - start building instantly with a live example",
|
|
6
6
|
"bin": {
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"build:cjs": "tsc -p tsconfig.cjs.json && mv dist/cjs/create.js dist/cjs/create.cjs",
|
|
28
28
|
"build:esm": "tsc -p tsconfig.esm.json",
|
|
29
29
|
"build": "npm run build:cjs && npm run build:esm",
|
|
30
|
+
"test": "node --test test/*.test.mjs",
|
|
30
31
|
"prepare": "npm run build"
|
|
31
32
|
},
|
|
32
33
|
|
|
@@ -4,6 +4,8 @@ import tcConfig from '../../../tidecloak.json'
|
|
|
4
4
|
|
|
5
5
|
const ALLOWED_ROLE = 'offline_access'
|
|
6
6
|
|
|
7
|
+
// Accepts plain Bearer tokens only. If you turn on useDPoP, call this with
|
|
8
|
+
// secureFetch and extend it to accept the DPoP scheme and validate the proof server-side.
|
|
7
9
|
export async function GET(request) {
|
|
8
10
|
const authHeader = request.headers.get('authorization')
|
|
9
11
|
if (!authHeader?.startsWith('Bearer ')) {
|
|
@@ -12,7 +12,7 @@ export default function HomePage() {
|
|
|
12
12
|
const [verifyResult, setVerifyResult] = useState(null)
|
|
13
13
|
const [verifying, setVerifying] = useState(false)
|
|
14
14
|
|
|
15
|
-
// Self encrypt/decrypt: data is bound to THIS user's identity
|
|
15
|
+
// Self encrypt/decrypt: data is bound to THIS user's identity, so only they can
|
|
16
16
|
// decrypt it. The "message" tag matches the _tide_message.selfencrypt/.selfdecrypt
|
|
17
17
|
// roles granted to every user in init/realm.json.
|
|
18
18
|
const TAG = "message"
|
|
@@ -71,7 +71,7 @@ export default function HomePage() {
|
|
|
71
71
|
|
|
72
72
|
// Submit = encrypt the current value, persist the ciphertext, then decrypt it
|
|
73
73
|
// straight back so the field keeps showing plaintext. We store only the
|
|
74
|
-
// ciphertext (here in localStorage; in a real app, on your server)
|
|
74
|
+
// ciphertext (here in localStorage; in a real app, on your server), and it's
|
|
75
75
|
// decrypted again when you log back in.
|
|
76
76
|
const onSubmit = useCallback(async () => {
|
|
77
77
|
setBusy(true); setCryptoErr(""); setStatus("")
|
|
@@ -120,7 +120,7 @@ export default function HomePage() {
|
|
|
120
120
|
<div style={{ marginTop: '1.5rem', borderTop: '1px solid #eee', paddingTop: '1rem', textAlign: 'left' }}>
|
|
121
121
|
<h2 style={{ fontSize: '1.1rem', margin: '0 0 0.25rem' }}>Your encrypted note</h2>
|
|
122
122
|
<p style={{ margin: '0 0 0.5rem', color: '#777', fontSize: '0.85rem' }}>
|
|
123
|
-
This is an encrypted textbox under your own identity
|
|
123
|
+
This is an encrypted textbox under your own identity. Only you can decrypt it.
|
|
124
124
|
</p>
|
|
125
125
|
|
|
126
126
|
<textarea
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Only reachable with a valid token: proxy.js checks it before this page renders.
|
|
2
|
+
export default function ProtectedPage() {
|
|
3
|
+
return (
|
|
4
|
+
<div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
5
|
+
<p>This page is protected server-side by proxy.js.</p>
|
|
6
|
+
</div>
|
|
7
|
+
)
|
|
8
|
+
}
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import fs from "fs"
|
|
2
2
|
import path from "path"
|
|
3
3
|
|
|
4
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
5
4
|
// Tide DPoP resource-server endpoint.
|
|
6
5
|
//
|
|
7
|
-
// DPoP is
|
|
8
|
-
//
|
|
6
|
+
// DPoP is opt-in. This route is only used when you pass `useDPoP` in the
|
|
7
|
+
// provider config; without it nothing requests this page and you can delete it.
|
|
8
|
+
// With DPoP on, the SDK loads this page from your own origin at:
|
|
9
9
|
// /tide_dpop/iss/<issuer-hex>/aud/<client-hex>/tide_dpop_auth.html
|
|
10
10
|
//
|
|
11
|
-
// This catch-all route serves the
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// script/style
|
|
15
|
-
//
|
|
16
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
11
|
+
// This catch-all route serves the bundled `public/tide_dpop_auth.html` for any
|
|
12
|
+
// such path, with the two response headers Tide requires:
|
|
13
|
+
// - Content-Security-Policy: the sha256 hashes pin the file's inline
|
|
14
|
+
// script/style, so only that exact code runs.
|
|
15
|
+
// - Allow-CSP-From: *, which lets the ORK embed this page cross-origin.
|
|
17
16
|
|
|
18
17
|
const htmlPath = path.join(process.cwd(), "public", "tide_dpop_auth.html")
|
|
19
18
|
|
|
@@ -15,8 +15,9 @@ set -euo pipefail
|
|
|
15
15
|
# It resolves everything relative to SCRIPT_DIR and is runnable from anywhere.
|
|
16
16
|
#
|
|
17
17
|
# The governance body below (from "Helper: grab a fresh master admin-cli
|
|
18
|
-
# token" onward) is IDENTICAL to the canonical init/tcinit.sh
|
|
19
|
-
#
|
|
18
|
+
# token" onward) is IDENTICAL to the canonical init/tcinit.sh, and
|
|
19
|
+
# test/tcinit-sync.test.mjs fails if they drift. Only this path/bootstrap
|
|
20
|
+
# preamble differs.
|
|
20
21
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
21
22
|
|
|
22
23
|
# ─── Resolve script directory (run from anywhere) ────────────────────────────
|
|
@@ -64,7 +65,7 @@ KC_USER="${KC_USER:-admin}"
|
|
|
64
65
|
KC_PASSWORD="${KC_PASSWORD:-password}"
|
|
65
66
|
CLIENT_NAME="${CLIENT_NAME:-myclient}"
|
|
66
67
|
SUBSCRIPTION_EMAIL="${SUBSCRIPTION_EMAIL:-test@demo.org}"
|
|
67
|
-
ADAPTER_OUTPUT_PATH="${ADAPTER_OUTPUT_PATH:-${SCRIPT_DIR}
|
|
68
|
+
ADAPTER_OUTPUT_PATH="${ADAPTER_OUTPUT_PATH:-${SCRIPT_DIR}/../tidecloak.json}"
|
|
68
69
|
MARKER_DIR="${SCRIPT_DIR}"
|
|
69
70
|
|
|
70
71
|
# ─── Find realm.json robustly ────────────────────────────────────────────────
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "next dev",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"next": "16.x",
|
|
13
13
|
"react": "19.x",
|
|
14
14
|
"react-dom": "19.x",
|
|
15
|
-
"@tidecloak/nextjs": "0.
|
|
15
|
+
"@tidecloak/nextjs": "^0.13.11"
|
|
16
16
|
},
|
|
17
17
|
"overrides": {
|
|
18
18
|
"postcss": "^8.5.25",
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
//
|
|
2
|
-
import { NextResponse } from "next/server";
|
|
3
|
-
import {
|
|
4
|
-
import tcConfig from "./tidecloak.json";
|
|
5
|
-
|
|
6
|
-
//
|
|
7
|
-
export
|
|
8
|
-
config: tcConfig,
|
|
9
|
-
protectedRoutes:{
|
|
10
|
-
// "offline_access" is granted to every authenticated user, so this protects
|
|
11
|
-
// the route for "any logged-in user". Swap it for a real realm/client role
|
|
12
|
-
// (e.g. "appUser") to demonstrate role-based access control.
|
|
13
|
-
"/protected": ["offline_access"]
|
|
14
|
-
},
|
|
15
|
-
onFailure: (ctx, req) => {
|
|
16
|
-
console.debug("Token verification failed");
|
|
17
|
-
return NextResponse.json(
|
|
18
|
-
{ error: 'Access forbidden: invalid token' },
|
|
19
|
-
{ status: 403 }
|
|
20
|
-
)
|
|
21
|
-
},
|
|
22
|
-
onSuccess: (ctx, req) => {
|
|
23
|
-
return NextResponse.next();
|
|
24
|
-
},
|
|
25
|
-
//
|
|
26
|
-
onError: (err, req) => {
|
|
27
|
-
console.error("[
|
|
28
|
-
return NextResponse.redirect(new URL("/auth/redirect", req.url));
|
|
29
|
-
}
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
//Which
|
|
33
|
-
export const config = {
|
|
34
|
-
matcher: ["/protected", "/protected/:path*"],
|
|
35
|
-
};
|
|
1
|
+
// Example Next.js proxy that verifies the access token server-side before a protected page loads.
|
|
2
|
+
import { NextResponse } from "next/server";
|
|
3
|
+
import { createTideCloakProxy } from "@tidecloak/nextjs/server";
|
|
4
|
+
import tcConfig from "./tidecloak.json";
|
|
5
|
+
|
|
6
|
+
// List every secure page and the roles allowed to see it
|
|
7
|
+
export const proxy = createTideCloakProxy({
|
|
8
|
+
config: tcConfig,
|
|
9
|
+
protectedRoutes: {
|
|
10
|
+
// "offline_access" is granted to every authenticated user, so this protects
|
|
11
|
+
// the route for "any logged-in user". Swap it for a real realm/client role
|
|
12
|
+
// (e.g. "appUser") to demonstrate role-based access control.
|
|
13
|
+
"/protected": ["offline_access"]
|
|
14
|
+
},
|
|
15
|
+
onFailure: (ctx, req) => {
|
|
16
|
+
console.debug("Token verification failed");
|
|
17
|
+
return NextResponse.json(
|
|
18
|
+
{ error: 'Access forbidden: invalid token' },
|
|
19
|
+
{ status: 403 }
|
|
20
|
+
)
|
|
21
|
+
},
|
|
22
|
+
onSuccess: (ctx, req) => {
|
|
23
|
+
return NextResponse.next();
|
|
24
|
+
},
|
|
25
|
+
// onError receives (err, req): the error is the first argument.
|
|
26
|
+
onError: (err, req) => {
|
|
27
|
+
console.error("[Proxy] ", err);
|
|
28
|
+
return NextResponse.redirect(new URL("/auth/redirect", req.url));
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
// Which paths the proxy runs on (the bare path and its subpaths)
|
|
33
|
+
export const config = {
|
|
34
|
+
matcher: ["/protected", "/protected/:path*"],
|
|
35
|
+
};
|
|
@@ -4,6 +4,8 @@ import tcConfig from '../../../tidecloak.json'
|
|
|
4
4
|
|
|
5
5
|
const ALLOWED_ROLE = 'offline_access'
|
|
6
6
|
|
|
7
|
+
// Accepts plain Bearer tokens only. If you turn on useDPoP, call this with
|
|
8
|
+
// secureFetch and extend it to accept the DPoP scheme and validate the proof server-side.
|
|
7
9
|
export async function GET(request: NextRequest): Promise<NextResponse> {
|
|
8
10
|
const authHeader = request.headers.get('authorization')
|
|
9
11
|
if (!authHeader?.startsWith('Bearer ')) {
|
|
@@ -19,7 +19,7 @@ export default function HomePage() {
|
|
|
19
19
|
const [verifyResult, setVerifyResult] = useState<string | null>(null)
|
|
20
20
|
const [verifying, setVerifying] = useState(false)
|
|
21
21
|
|
|
22
|
-
// Self encrypt/decrypt: data is bound to THIS user's identity
|
|
22
|
+
// Self encrypt/decrypt: data is bound to THIS user's identity, so only they can
|
|
23
23
|
// decrypt it. The "message" tag matches the _tide_message.selfencrypt/.selfdecrypt
|
|
24
24
|
// roles granted to every user in init/realm.json.
|
|
25
25
|
const TAG = "message"
|
|
@@ -79,7 +79,7 @@ export default function HomePage() {
|
|
|
79
79
|
|
|
80
80
|
// Submit = encrypt the current value, persist the ciphertext, then decrypt it
|
|
81
81
|
// straight back so the field keeps showing plaintext. We store only the
|
|
82
|
-
// ciphertext (here in localStorage; in a real app, on your server)
|
|
82
|
+
// ciphertext (here in localStorage; in a real app, on your server), and it's
|
|
83
83
|
// decrypted again when you log back in.
|
|
84
84
|
const onSubmit = useCallback(async () => {
|
|
85
85
|
setBusy(true); setCryptoErr(""); setStatus("")
|
|
@@ -126,7 +126,7 @@ export default function HomePage() {
|
|
|
126
126
|
<div style={{ marginTop: '1.5rem', borderTop: '1px solid #eee', paddingTop: '1rem', textAlign: 'left' }}>
|
|
127
127
|
<h2 style={{ fontSize: '1.1rem', margin: '0 0 0.25rem' }}>Your encrypted note</h2>
|
|
128
128
|
<p style={{ margin: '0 0 0.5rem', color: '#777', fontSize: '0.85rem' }}>
|
|
129
|
-
This is an encrypted textbox under your own identity
|
|
129
|
+
This is an encrypted textbox under your own identity. Only you can decrypt it.
|
|
130
130
|
</p>
|
|
131
131
|
|
|
132
132
|
<textarea
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Only reachable with a valid token: proxy.ts checks it before this page renders.
|
|
2
|
+
export default function ProtectedPage() {
|
|
3
|
+
return (
|
|
4
|
+
<div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
5
|
+
<p>This page is protected server-side by proxy.ts.</p>
|
|
6
|
+
</div>
|
|
7
|
+
)
|
|
8
|
+
}
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import fs from "fs"
|
|
2
2
|
import path from "path"
|
|
3
3
|
|
|
4
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
5
4
|
// Tide DPoP resource-server endpoint.
|
|
6
5
|
//
|
|
7
|
-
// DPoP is
|
|
8
|
-
//
|
|
6
|
+
// DPoP is opt-in. This route is only used when you pass `useDPoP` in the
|
|
7
|
+
// provider config; without it nothing requests this page and you can delete it.
|
|
8
|
+
// With DPoP on, the SDK loads this page from your own origin at:
|
|
9
9
|
// /tide_dpop/iss/<issuer-hex>/aud/<client-hex>/tide_dpop_auth.html
|
|
10
10
|
//
|
|
11
|
-
// This catch-all route serves the
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// script/style
|
|
15
|
-
//
|
|
16
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
11
|
+
// This catch-all route serves the bundled `public/tide_dpop_auth.html` for any
|
|
12
|
+
// such path, with the two response headers Tide requires:
|
|
13
|
+
// - Content-Security-Policy: the sha256 hashes pin the file's inline
|
|
14
|
+
// script/style, so only that exact code runs.
|
|
15
|
+
// - Allow-CSP-From: *, which lets the ORK embed this page cross-origin.
|
|
17
16
|
|
|
18
17
|
const htmlPath = path.join(process.cwd(), "public", "tide_dpop_auth.html")
|
|
19
18
|
|
|
@@ -15,8 +15,9 @@ set -euo pipefail
|
|
|
15
15
|
# It resolves everything relative to SCRIPT_DIR and is runnable from anywhere.
|
|
16
16
|
#
|
|
17
17
|
# The governance body below (from "Helper: grab a fresh master admin-cli
|
|
18
|
-
# token" onward) is IDENTICAL to the canonical init/tcinit.sh
|
|
19
|
-
#
|
|
18
|
+
# token" onward) is IDENTICAL to the canonical init/tcinit.sh, and
|
|
19
|
+
# test/tcinit-sync.test.mjs fails if they drift. Only this path/bootstrap
|
|
20
|
+
# preamble differs.
|
|
20
21
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
21
22
|
|
|
22
23
|
# ─── Resolve script directory (run from anywhere) ────────────────────────────
|
|
@@ -64,7 +65,7 @@ KC_USER="${KC_USER:-admin}"
|
|
|
64
65
|
KC_PASSWORD="${KC_PASSWORD:-password}"
|
|
65
66
|
CLIENT_NAME="${CLIENT_NAME:-myclient}"
|
|
66
67
|
SUBSCRIPTION_EMAIL="${SUBSCRIPTION_EMAIL:-test@demo.org}"
|
|
67
|
-
ADAPTER_OUTPUT_PATH="${ADAPTER_OUTPUT_PATH:-${SCRIPT_DIR}
|
|
68
|
+
ADAPTER_OUTPUT_PATH="${ADAPTER_OUTPUT_PATH:-${SCRIPT_DIR}/../tidecloak.json}"
|
|
68
69
|
MARKER_DIR="${SCRIPT_DIR}"
|
|
69
70
|
|
|
70
71
|
# ─── Find realm.json robustly ────────────────────────────────────────────────
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "next dev",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"next": "16.x",
|
|
13
13
|
"react": "19.x",
|
|
14
14
|
"react-dom": "19.x",
|
|
15
|
-
"@tidecloak/nextjs": "0.
|
|
15
|
+
"@tidecloak/nextjs": "^0.13.11"
|
|
16
16
|
},
|
|
17
17
|
"overrides": {
|
|
18
18
|
"postcss": "^8.5.25",
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Example Next.js proxy that verifies the access token server-side before a protected page loads.
|
|
2
2
|
import type { NextRequest } from "next/server";
|
|
3
3
|
import { NextResponse } from "next/server";
|
|
4
|
-
import {
|
|
4
|
+
import { createTideCloakProxy } from "@tidecloak/nextjs/server";
|
|
5
5
|
import type { TidecloakConfig } from "@tidecloak/nextjs/server";
|
|
6
6
|
import rawConfig from "./tidecloak.json";
|
|
7
7
|
|
|
8
8
|
// tidecloak.json is a placeholder ({}) until `npm run init` provisions the realm
|
|
9
9
|
// and writes the real adapter config. Type it via the SDK's own config shape so
|
|
10
|
-
// the
|
|
10
|
+
// the proxy options type-check regardless of the placeholder's contents.
|
|
11
11
|
const tcConfig = rawConfig as TidecloakConfig;
|
|
12
12
|
|
|
13
|
-
export
|
|
13
|
+
export const proxy = createTideCloakProxy({
|
|
14
14
|
config: tcConfig,
|
|
15
15
|
protectedRoutes: {
|
|
16
16
|
// "offline_access" is granted to every authenticated user, so this protects
|
|
@@ -31,16 +31,16 @@ export default createTideCloakMiddleware({
|
|
|
31
31
|
onSuccess: (ctx: { payload: Record<string, any> }, req: NextRequest) => {
|
|
32
32
|
return NextResponse.next();
|
|
33
33
|
},
|
|
34
|
-
//
|
|
34
|
+
// onError receives (err, req): the error is the first argument.
|
|
35
35
|
onError: (err: unknown, req: NextRequest) => {
|
|
36
|
-
console.error("[
|
|
36
|
+
console.error("[Proxy] error verifying token for", req.nextUrl.pathname, err);
|
|
37
37
|
// if something unexpected happens, redirect to your auth flow
|
|
38
38
|
const redirectUrl = new URL("/auth/redirect", req.url);
|
|
39
39
|
return NextResponse.redirect(redirectUrl);
|
|
40
40
|
},
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
-
//
|
|
43
|
+
// Which paths the proxy runs on (the bare path and its subpaths)
|
|
44
44
|
export const config = {
|
|
45
45
|
matcher: ["/protected", "/protected/:path*"],
|
|
46
46
|
};
|