Tutorial: Build a TideCloak + Next.js App from Scratch
Scaffold a fresh Next.js app wired to TideCloak, with auth, middleware, and optional QEA (Quorum Enforced Authorization) - in minutes.
1) Prerequisites
- A TideCloak server you manage (dev or hosted). For dev, you can run the Docker image locally.
- Node.js 20.9 or later (required by Next.js 16, which the template uses)
curlandjq, used by the initializer
2) Initialize the template project
The initializer can create the realm and clients on your TideCloak server (including Tide Realm Admin creation and QEA enablement).
Install curl and jq if you don't have them (Debian/Ubuntu example):
sudo apt update && sudo apt install -y curl jq
Run the initializer and answer its prompts. The defaults work for a local dev server; choose TypeScript to get the files shown below.
npm init @tidecloak/nextjs@latest my-app
Complete Tide enrolment when the initializer asks
Once the prompts are answered, the initializer creates the realm and generates the app, then stops and prints a line like this:
ACTION REQUIRED: Open this URL and complete Tide enrollment: https://...
That link sets up the Tide account for your realm's first admin. Open it, finish enrolment in the Tide enclave, and leave the initializer running. It polls for the new account and finishes on its own once enrolment lands. The enclave step can take a few minutes.
Until enrolment completes there is no first admin, so the realm is unfinished and the app has nothing working to start against.
Project structure (generated)
my-app/├── app/│ ├── api/│ │ └── protected/│ │ └── route.ts│ ├── auth/│ │ └── redirect/│ │ └── page.tsx│ ├── home/│ │ └── page.tsx│ ├── tide_dpop/│ │ └── [...path]/│ │ └── route.ts│ ├── layout.tsx│ └── page.tsx├── init/│ ├── realm.json│ └── tcinit.sh├── public/│ ├── silent-check-sso.html│ └── tide_dpop_auth.html├── middleware.ts├── next.config.js├── package.json├── tidecloak.json└── tsconfig.json
app/page.tsx: login pageapp/home/page.tsx: landing page after login, with an encrypted note and a Verify Token buttonapp/auth/redirect/page.tsx: redirect target after login and logoutapp/api/protected/route.ts: API route that verifies the access tokenapp/tide_dpop/[...path]/route.ts: servespublic/tide_dpop_auth.htmlwith the headers Tide's DPoP flow needsmiddleware.ts: verifies the token on/protectedroutes. Next.js 16 warns that themiddlewarefile convention is deprecated in favour ofproxy; the app still builds and runs.tidecloak.json: your adapter config, written by the initializerinit/: the realm template and script the initializer runs. Runnpm run initto run it again later.
The JavaScript template has the same layout with .jsx and .js files.
3) Run the app
cd my-appnpm install
npm run dev
Open http://localhost:3000. You should see the Welcome! login page.
Expanding from the template
Implementing encryption/decryption
The template's realm already grants every user the _tide_message.selfencrypt and _tide_message.selfdecrypt roles, which app/home/page.tsx uses to encrypt and decrypt a note. To encrypt data under other tags, first set up encrypt/decrypt roles for them.
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).
Syntax Overview
// Encrypt payloads:const encryptedArray = await doEncrypt([{ data: /* string */, tags: ['tag1', 'tag2'] },// ...]);// Decrypt blobs:const decryptedArray = await doDecrypt([{ encrypted: /* string from doEncrypt */, tags: ['tag1', 'tag2'] },// ...]);
Order guarantee: the returned array matches the input order.
- Encryption requires access token roles
_tide_<tag>.selfencryptfor each tag. - Decryption requires access token roles
_tide_<tag>.selfdecryptfor each tag.