TideCloak Verify SDK
A lightweight utility for server‑side verification of TideCloak‑issued JSON Web Tokens (JWTs).
This package exports a single function,
verifyTideCloakToken, which you can use in your Next.js API routes, Node.js servers, or any backend to verify the authenticity, issuer, audience, and roles of a JWT issued by your TideCloak realm.
---
Installation
``
bash
npm install @tidecloak/verify
or
yarn add @tidecloak/verify
`
---
Import
`
ts
import { verifyTideCloakToken } from '@tidecloak/verify';
`
---
API
$3
| Parameter | Type | Description |
| -------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------- |
| config
| object
| Your TideCloak adapter JSON (the Tidecloak client configuration you download from your realm settings). |
| token
| string
| The raw JWT (access token) to verify. |
| allowedRoles
| string[]
(optional) | Array of Tidecloak realm or client roles. If provided, the user must have at least one of these roles in their token. |
Returns:
Promise
* Success: Decoded token payload when all checks pass.
* Failure: null if verification fails or the user lacks the required role(s).
#### Under the hood
Internally, verifyTideCloakToken uses the jose library to:
1. Ensure a token is present.
2. Construct the correct issuer URL from config['auth-server-url'] and config.realm.
3. Choose between a local JWK Set (config.jwk.keys) or fetch the JWK Set remotely from Tidecloak.
4. Verify the token's signature, issuer, and azp (authorized party) against config.resource.
5. Extract realm (payload.realm_access.roles) and client (payload.resource_access[resource].roles) roles.
6. Check for at least one matching role if allowedRoles is specified.
On any failure, it logs an error to the console and returns null.
---
Examples
$3
> ESM / import syntax (add { "type": "module" } in your package.json):
`js
// server.js
import express from 'express';
import cookieParser from 'cookie-parser';
import { verifyTideCloakToken } from '@tidecloak/verify';
import config from './tidecloakAdapter.json';
const app = express();
app.use(cookieParser());
app.get('/secure', async (req, res) => {
const token = req.cookies.kcToken || req.headers.authorization?.split(' ')[1] || '';
const payload = await verifyTideCloakToken(config, token, ['user']);
if (!payload) {
return res.status(401).json({ error: 'Unauthorized' });
}
res.json({ message: Hello, ${payload.preferred_username} });
});
app.listen(3000, () => console.log('Server running on port 3000'));
`
> CommonJS / require syntax (default Node.js):
``js
// server.js
const express = require('express');
const cookieParser = require('cookie-parser');
const { verifyTideCloakToken } = require('@tidecloak/verify');
const config = require('./tidecloakAdapter.json');
const app = express();
app.use(cookieParser());
app.get('/secure', async (req, res) => {
const token = req.cookies.kcToken || req.headers.authorization?.split(' ')[1] || '';
const payload = await verifyTideCloakToken(config, token, ['user']);
if (!payload) {
return res.status(401).json({ error: 'Unauthorized' });
}
res.json({ message: Hello, ${payload.preferred_username} });
});
app.listen(3000, () => console.log('Server running on port 3000'));
``
$3
`jsx
// pages/secure.js (Next.js Pages Router)
import React from 'react';
import { verifyTideCloakToken } from '@tidecloak/verify';
import config from '../tidecloakAdapter.json';
export async function getServerSideProps({ req }) {
const token = req.cookies.kcToken || req.headers.authorization?.split(' ')[1] || '';
const payload = await verifyTideCloakToken(config, token, ['user']);
if (!payload) {
return { redirect: { destination: '/login', permanent: false } };
}
return { props: { user: payload.preferred_username } };
}
export default function SecurePage({ user }) {
return Welcome, {user}
;
}
`
$3
`ts
// pages/api/secure.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { verifyTideCloakToken } from '@tidecloak/verify';
import config from '../../tidecloakAdapter.json';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const token = req.cookies.kcToken || req.headers.authorization?.split(' ')[1] || '';
const payload = await verifyTideCloakToken(config, token, ['user', 'admin']);
if (!payload) {
return res.status(401).json({ error: 'Unauthorized' });
}
res.status(200).json({ message: 'Hello, ' + payload.preferred_username });
}
`
$3
`ts
// app/api/secure/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { verifyTideCloakToken } from '@tidecloak/verify';
import config from '../../../tidecloakAdapter.json';
export async function GET(req: NextRequest) {
const token = req.cookies.get('kcToken')?.value || '';
const payload = await verifyTideCloakToken(config, token, ['user']);
if (!payload) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
return NextResponse.json({ message: Welcome, ${payload.preferred_username} });
}
`
---
TypeScript Definitions
`ts
interface TidecloakConfig {
realm: string;
'auth-server-url': string;
resource: string;
publicClient?: boolean;
confidentialPort?: number;
jwk?: { keys: Array<{ kid: string; kty: string; alg: string; use: string; x: string; crv?: string }> };
[key: string]: unknown;
}
export declare function verifyTideCloakToken(
config: TidecloakConfig,
token: string,
allowedRoles?: string[]
): Promise | null>;
``
---