SDKsNode.js SDK
Express.js
Integrate HelloJohn authentication into Express.js apps — middleware, protected routes, and request augmentation.
Express.js
Use HelloJohn with Express.js to protect routes, verify tokens, and access user data in request handlers.
Installation
npm install @hellojohn/nodeSetup
import express from "express";
import { HelloJohn } from "@hellojohn/node";
const app = express();
const hj = new HelloJohn({
tenantId: process.env.HELLOJOHN_TENANT_ID!,
secretKey: process.env.HELLOJOHN_SECRET_KEY!,
});
app.use(express.json());Authentication Middleware
import type { Request, Response, NextFunction } from "express";
// Extend the Request type
declare global {
namespace Express {
interface Request {
auth?: {
userId: string;
sessionId: string;
orgId: string | null;
orgRole: string | null;
};
}
}
}
async function requireAuth(req: Request, res: Response, next: NextFunction) {
const token = req.headers.authorization?.replace("Bearer ", "");
if (!token) {
return res.status(401).json({ error: "Missing Authorization header" });
}
try {
const payload = await hj.verifyToken(token);
req.auth = {
userId: payload.sub as string,
sessionId: payload.sid as string,
orgId: (payload.org_id as string) ?? null,
orgRole: (payload.org_role as string) ?? null,
};
next();
} catch {
res.status(401).json({ error: "Invalid or expired token" });
}
}Protected Routes
// Public routes
app.get("/api/health", (req, res) => res.json({ ok: true }));
// Protected routes
app.get("/api/me", requireAuth, async (req, res) => {
const user = await hj.users.get(req.auth!.userId);
res.json(user);
});
app.post("/api/posts", requireAuth, async (req, res) => {
const post = await db.post.create({
data: {
...req.body,
authorId: req.auth!.userId,
},
});
res.status(201).json(post);
});Role-Based Middleware
function requireRole(role: string) {
return (req: Request, res: Response, next: NextFunction) => {
if (!req.auth) {
return res.status(401).json({ error: "Unauthorized" });
}
if (req.auth.orgRole !== role && req.auth.orgRole !== "owner") {
return res.status(403).json({ error: "Insufficient permissions" });
}
next();
};
}
// Admin-only route
app.delete(
"/api/users/:id",
requireAuth,
requireRole("admin"),
async (req, res) => {
await hj.users.delete(req.params.id);
res.status(204).send();
}
);Router-Level Auth
Apply middleware to a group of routes:
import { Router } from "express";
const apiRouter = Router();
apiRouter.use(requireAuth); // All routes in this router require auth
apiRouter.get("/profile", async (req, res) => {
const user = await hj.users.get(req.auth!.userId);
res.json(user);
});
apiRouter.get("/orders", async (req, res) => {
const orders = await db.order.findMany({
where: { userId: req.auth!.userId },
});
res.json(orders);
});
app.use("/api", apiRouter);Using the Admin SDK
Perform server-side user management:
// Get a user
const user = await hj.users.get(userId);
// Update a user
await hj.users.update(userId, { firstName: "Jane" });
// Revoke all sessions
await hj.sessions.revokeAll(userId);
// List org members
const members = await hj.organizations.listMembers(orgId);Error Handling
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
if (err.name === "HelloJohnError") {
return res.status(401).json({ error: err.message });
}
console.error(err);
res.status(500).json({ error: "Internal server error" });
});