npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@antzsoft/wso2-auth-backend

v1.0.0

Published

Node.js backend SDK for Antz Central User Service (WSO2 IS 7.2.0) — M2M SCIM2 user management, JWT verification, admin & self-service password flows.

Readme

@antzsoft/wso2-auth-backend

Node.js backend SDK for Antz Central User Service (WSO2 IS 7.2.0). Wraps the machine-to-machine (client_credentials) SCIM2 user-management API, admin and self-service password flows, local JWT verification via JWKS, and OIDC session/logout helpers — everything a backend needs to integrate without hand-rolling fetch calls against WSO2 directly.

Companion to @antzsoft/wso2-auth-web (browser/frontend) and @antzsoft/wso2-auth-reactnative — this package is the server-side counterpart, built from the same API surface documented in docs/backend-api-integration-guide.md.

Contents

Installation

npm install @antzsoft/wso2-auth-backend

Requires Node.js 18+ (uses the global fetch). Ships as dual ESM + CommonJS — import and require() both work.

Quick Start

import { AntzBackendClient } from "@antzsoft/wso2-auth-backend";

const antz = new AntzBackendClient({
  baseUrl: process.env.WSO2_BASE_URL!,       // e.g. https://auth.antzsystems.com
  tenant: process.env.WSO2_TENANT!,          // "prod" | "dev" | "uat"
  clientId: process.env.WSO2_CLIENT_ID!,
  clientSecret: process.env.WSO2_CLIENT_SECRET!,
});

const user = await antz.users.createUser({
  userName: "[email protected]",
  email: "[email protected]",
  givenName: "John",
  familyName: "Doe",
  phone: "+919876543210",
});

The M2M token is fetched lazily on the first call and cached in memory (refreshed ~60s before it expires) — you never need to manage it yourself.

Configuration

interface AntzBackendConfig {
  baseUrl: string;                    // "https://auth.antzsystems.com"
  tenant: string;                     // "prod" | "dev" | "uat"
  clientId: string;
  clientSecret: string;
  scope?: string;                     // defaults to the full user-mgt scope set
  audience?: string;                  // expected `aud` claim on verified tokens; omit to skip the check
  tokenRefreshMarginSeconds?: number; // default 60
  jwksCacheMaxAgeMs?: number;         // default 24h
}

Store clientId/clientSecret in your secrets manager, not in source or plain .env files committed to the repo.

User Management

antz.users — see Section 3–5 of the integration guide for full request/response shapes.

// Create — omit `password` to use the auto-generated-password + SMS/email notification flow
await antz.users.createUser({ userName: "alice", phone: "+919876543210" });

// Lookup — email/username use SCIM filters; phone uses a dedicated lookup endpoint
const { exists, user } = await antz.users.validateUserExists("email", "[email protected]");
const byPhone = await antz.users.validateUserExists("phone", "+919876543210");

await antz.users.getUser(wso2UserId);
await antz.users.listUsers({ startIndex: 1, count: 20 }); // no sortBy — unsupported by WSO2 IS 7.2.0

// Update — only supplied fields change
await antz.users.updateUser(wso2UserId, { active: false });                 // deactivate
await antz.users.updateUser(wso2UserId, { unlockAccount: true });           // unlock after failed logins
await antz.users.updateUser(wso2UserId, { antzzooids: ["ZOO-001"] });       // replace the full Zoo ID list
await antz.users.updateUser(wso2UserId, { addAntzzooids: ["ZOO-003"] });    // append without removing existing

await antz.users.deleteUser(wso2UserId); // permanent — prefer { active: false } in most cases

antzuserid is single-value; antzzooids is multi-value — pass an array even for one Zoo ID, and use addAntzzooids (SCIM op: add) instead of antzzooids (SCIM op: replace) when you want to append rather than overwrite.

Bulk Update & Delete

WSO2's SCIM2 Bulk API batches independent per-user operations into one HTTP call. Not atomic — already-applied operations are not rolled back if a later one fails. You must already know the target wso2-uuids.

const results = await antz.users.bulkUpdateUsers([
  { id: wso2UserId1, active: false },
  { id: wso2UserId2, email: "[email protected]" },
]);
// results: [{ bulkId, ok, code, detail? }, ...] — check each entry, an overall success does not imply every op succeeded

await antz.users.bulkDeleteUsers([wso2UserId1, wso2UserId2]); // permanent

Password Flows

antz.password

// Admin reset — silent, no notification
await antz.password.adminResetPassword(wso2UserId, "NewPassword123!");

// Admin reset — WSO2 notifies the user via SMS/email with the new password
// (requires the M2M token to be JWT, not opaque)
await antz.password.adminResetPasswordAndNotify(wso2UserId, "NewPassword123!");

// Self-service — requires the USER's own Bearer token, never the M2M token
const otpStatus = await antz.password.sendChangePasswordOtp(userAccessToken);
if (otpStatus.ok || otpStatus.code === "OTP_NOT_ENABLED") {
  const result = await antz.password.changePassword(
    userAccessToken,
    "OldPassword123!",
    "NewPassword456@",
    otpStatus.ok ? "123456" : undefined,
  );
}

// Or throw instead of returning a result object:
await antz.password.changePasswordOrThrow(userAccessToken, "OldPassword123!", "NewPassword456@");

JWT Verification

antz.jwt — local verification against WSO2's JWKS, no network call per request. The JWKS response is cached (default 24h) and refetched automatically on a kid cache miss (key rotation).

try {
  const claims = await antz.jwt.verifyAccessToken(bearerToken);
  // claims.sub, claims.email, claims.phone_number, claims.scope, ...
} catch (err) {
  if (err instanceof AntzTokenVerificationError) {
    // err.code: "TOKEN_EXPIRED" | "INVALID_SIGNATURE" | "CLAIM_MISMATCH" | "INVALID_TOKEN"
  }
}

// Reshaped into common fields:
const verified = await antz.jwt.extractVerifiedClaims(bearerToken);
// { wso2Id, email, phone, firstName, lastName, username, tenant, scopes, issuedAt, expiresAt, clientId }

Express middleware example

async function authMiddleware(req, res, next) {
  const header = req.headers.authorization ?? "";
  const token = header.startsWith("Bearer ") ? header.slice(7) : null;
  if (!token) return res.status(401).json({ code: "MISSING_TOKEN" });

  try {
    req.user = await antz.jwt.verifyAccessToken(token);
    next();
  } catch (err) {
    const code = err instanceof AntzTokenVerificationError ? err.code : "INVALID_TOKEN";
    res.status(401).json({ code });
  }
}

Decode without verifying (debugging only)

import { decodeTokenUnsafe } from "@antzsoft/wso2-auth-backend";
decodeTokenUnsafe(token); // no signature check — never use for authorization decisions

Introspection (opaque tokens only)

const result = await antz.jwt.introspect(token, clientId, clientSecret);
if (!result.active) { /* expired or revoked */ }

Prefer verifyAccessToken for JWTs — introspection costs a network round-trip to WSO2 on every call.

Session Helpers

antz.session and the standalone assertExpectedUser guard — for backends that drive the OIDC flow directly (no Antz frontend SDK), e.g. server-rendered integrations like odoo or ThingsBoard.

Cross-app SSO mismatch guard

WSO2 keeps one login session per browser (commonAuthId), shared across every app. A second app's /authorize call can silently get back a token for whichever user is already signed in elsewhere — regardless of which username that app just collected and verified. Call this right after exchanging the authorization code, passing the username your app expected:

import { assertExpectedUser, AntzSessionUserMismatchError } from "@antzsoft/wso2-auth-backend";

try {
  assertExpectedUser(tokens.id_token, expectedUsername);
} catch (err) {
  if (err instanceof AntzSessionUserMismatchError) {
    // tell the user to log out of the other app first
  }
}

Fail-open by design — a no-op if there's nothing to compare (e.g. the id_token's sub is a bare UUID and no email/username claim is configured on the WSO2 application).

Logout — local vs. full

// Local (app-only): revoke this app's refresh token; other apps stay signed in
await antz.session.revokeToken(refreshToken);

// Full (SSO-wide), back-channel: revoke + end the WSO2 session record
await antz.session.fullLogout(refreshToken, idToken);

// Full, front-channel: redirect the user's browser (required to clear the commonAuthId cookie)
const logoutUrl = antz.session.buildFrontChannelLogoutUrl(idToken, postLogoutRedirectUri);
res.redirect(logoutUrl);

Error Types

All errors extend AntzAuthError:

| Class | Thrown when | |---|---| | AntzTokenError | M2M token request failed | | AntzApiError | Any non-2xx SCIM/REST response (carries status/body) | | AntzUserExistsError | createUser hit a 409 conflict | | AntzUserNotFoundError | A single-user endpoint returned 404 | | AntzTokenVerificationError | JWT verification failed (.code: TOKEN_EXPIRED / INVALID_SIGNATURE / CLAIM_MISMATCH / INVALID_TOKEN / MISSING_TOKEN) | | AntzSessionUserMismatchError | Cross-app SSO session guard tripped | | AntzChangePasswordError | changePasswordOrThrow failed (.code, .status) |

Environment Routing

Set WSO2_TENANT (prod | dev | uat) as an environment variable so no code changes are needed when promoting across environments. Users are fully isolated per tenant — never mix tenant configs within a single backend deployment.