Wocha Docs

Express.js quickstart

Add Wocha authentication to an Express.js API with JWT access token validation on incoming requests and the Management SDK for admin tasks.

Add Wocha authentication to an Express.js API: validate JWT access tokens on incoming requests and use the Management SDK for admin tasks.

Prerequisites

  • Node.js 18+
  • A Wocha project with an OAuth application (Wocha Console)
  • An API audience configured if your tenant requires it (optional for basic JWT validation)

What you'll build

An Express API that validates Wocha JWTs on protected routes and uses the Management SDK for admin operations.

your-app.local

Welcome back

After sign-in

✓ Session stored securely

✓ User profile available in your app

✓ Organisation context ready for multi-tenant features

Installation

pnpm add @wocha/sdk express express-oauth2-jwt-bearer
Or scaffold with the CLI
npx @wocha/cli init --framework express

express-oauth2-jwt-bearer validates bearer tokens against your Wocha issuer JWKS.

Environment variables

Create a .env file:

# JWT validation (resource server)
WOCHA_ISSUER=https://your-tenant.auth.wocha.ai
WOCHA_AUDIENCE=your-api-audience          # optional — omit if not using audience claims
 
# Management API (server-side admin)
WOCHA_API_KEY=wocha_mgmt_...
WOCHA_TENANT=your-tenant-slug

Register your API as a resource in the Console if you use audience-scoped tokens.

JWT validation middleware

Create src/middleware/wocha.ts:

import { auth } from "express-oauth2-jwt-bearer";
 
export const requireAuth = auth({
  issuerBaseURL: process.env.WOCHA_ISSUER!,
  audience: process.env.WOCHA_AUDIENCE,
  tokenSigningAlg: "RS256",
});

This middleware:

  1. Extracts the Authorization: Bearer header
  2. Fetches signing keys from {WOCHA_ISSUER}/.well-known/jwks.json
  3. Validates signature, issuer, expiry, and audience

Protected route example

Create src/index.ts:

import express from "express";
import { WochaClient } from "@wocha/sdk";
import { requireAuth } from "./middleware/wocha";
 
const app = express();
app.use(express.json());
 
const wocha = new WochaClient({
  tenant: process.env.WOCHA_TENANT!,
  apiKey: process.env.WOCHA_API_KEY!,
});
 
/** Public health check */
app.get("/health", (_req, res) => {
  res.json({ status: "ok" });
});
 
/** Protected — requires a valid Wocha access token */
app.get("/api/me", requireAuth, (req, res) => {
  const payload = req.auth?.payload;
  res.json({
    userId: payload?.sub,
    email: payload?.email,
    orgId: payload?.org_id,
  });
});
 
/** Protected — list users via Management API (uses API key, not user token) */
app.get("/api/admin/users", requireAuth, async (_req, res) => {
  try {
    const users = await wocha.users.list({ pageSize: 10 });
    res.json(users);
  } catch (err) {
    res.status(500).json({ error: "Failed to list users" });
  }
});
 
const port = process.env.PORT ?? 3000;
app.listen(port, () => {
  console.log(`API listening on http://localhost:${port}`);
});

Testing the integration

  1. Start your API:

    node --env-file=.env dist/index.js
  2. Obtain an access token — sign in via your frontend app or request a token from the hosted login flow.

  3. Call the protected endpoint:

    curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" http://localhost:3000/api/me
  4. Confirm you receive the user claims. A missing or expired token returns 401 Unauthorized.

Next steps

On this page