Node.js (non-React)
For Express / Fastify / Koa / NestJS / Hono backends. Same pattern as the Python guide: proxy auth flows, validate JWTs locally.
Setup
npm install express axios jose cookie-parser
Express example
import express from 'express';
import axios from 'axios';
import cookieParser from 'cookie-parser';
import { createRemoteJWKSet, jwtVerify } from 'jose';
const AUTH_URL = process.env.AUTH_URL ?? 'http://auth:4000';
const app = express();
app.use(express.json());
app.use(cookieParser());
// ── proxy auth flows ────────────────────────────────────────
app.post('/auth/login', async (req, res) => {
const upstream = await axios.post(`${AUTH_URL}/v1/auth/login`, req.body, {
validateStatus: () => true,
});
// forward Set-Cookie headers
const setCookies = upstream.headers['set-cookie'];
if (setCookies) res.setHeader('Set-Cookie', setCookies);
res.status(upstream.status).json(upstream.data);
});
// ── validate JWT on protected routes ────────────────────────
const jwks = createRemoteJWKSet(new URL(`${AUTH_URL}/.well-known/jwks.json`));
async function requireAuth(req: any, res: any, next: any) {
const token =
req.cookies?.identsphere_at ??
req.headers.authorization?.replace(/^Bearer /, '');
if (!token) return res.status(401).json({ error: 'no token' });
try {
const { payload } = await jwtVerify(token, jwks);
req.user = payload;
next();
} catch (e) {
res.status(401).json({ error: 'invalid token' });
}
}
app.get('/api/me', requireAuth, (req: any, res) => {
res.json({ user_id: req.user.sub, org_id: req.user.org });
});
app.listen(3000);
Fastify
Same shape; Fastify's plugin model lets you wrap requireAuth as a
fastify-plugin for cleaner composition.
import Fastify from 'fastify';
const app = Fastify();
app.decorate('authenticate', requireAuth);
app.get('/api/me', { preHandler: app.authenticate }, async (req: any) => ({
user_id: req.user.sub,
}));
NestJS
Wrap as a CanActivate guard:
@Injectable()
export class AuthGuard implements CanActivate {
async canActivate(ctx: ExecutionContext): Promise<boolean> {
const req = ctx.switchToHttp().getRequest();
const token = req.cookies?.identsphere_at;
if (!token) return false;
const { payload } = await jwtVerify(token, jwks);
req.user = payload;
return true;
}
}
Calling auth endpoints from the backend
To make calls on behalf of the user, forward the cookies:
async function fetchProfile(req: express.Request) {
return axios.get(`${AUTH_URL}/v1/users/me`, {
headers: { Cookie: req.headers.cookie ?? '' },
});
}
Caveats
Same revocation lag as Pattern 2 (~JWKS cache TTL + access token TTL).
Shorten IDENTSPHERE_ACCESS_EXPIRY_SECS if you need tighter revocation.
Full Express starter
A complete example will live in examples/express-nodejs-starter/ in the
repo (coming v1.1).