@zanshield/sdk
v1.0.0
Published
Client library for integrating a system with ZanShield, eGAZ's multi-factor authentication service: builds signed, encrypted tickets and verifies ZanShield's acknowledgements.
Maintainers
Readme
ZanShield SDK for Node.js
Add ZanShield multi-factor authentication to your system's login. Your system checks the password; ZanShield handles the second factor, deciding whether the user sets up a first method or verifies an existing one. This package builds the ticket you send and checks the acknowledgement you get back.
Server-side only. Your system's private key must never reach a browser.
Install
npm install @zanshield/sdkRequires Node.js 18+. No dependencies; uses Node's built-in crypto. TypeScript types are included, and it works with both require and import.
Usage
const { ZanShieldClient, AcknowledgementRejectedError, loadPrivateKey, loadPublicKey } = require("@zanshield/sdk");
const client = new ZanShieldClient(
"PAYROLL01",
"EGAZ",
loadPrivateKey(fs.readFileSync("/secure/zanshield-private.pem")),
loadPublicKey(fs.readFileSync("/secure/zanshield-engine-public.pem")),
);
// 1. After the user's password is correct. fullName and mobile are optional;
// without a mobile number the user can't choose SMS codes.
const ticket = client.createTicket(user.id, user.email, { fullName: user.fullName, mobile: user.phone });
res.redirect(ZanShieldClient.portalUrl("https://portal.zanshield.devtech.co.tz", ticket));
// 2. At your redirect URI:
try {
const ack = client.acceptAcknowledgement(req.query.ticket);
startSessionFor(ack.userId);
} catch (e) {
if (!(e instanceof AcknowledgementRejectedError)) throw e; // not a valid ZanShield acknowledgement at all
// Genuine, but must not sign in: e.reason is NOT_AUTHENTICATED, EXPIRED or REPLAYED.
showError(e.acknowledgement.message);
}acceptAcknowledgement checks the signature, a successful verification (responseCode 9000), freshness (3 minutes by default; set maxAcknowledgementAgeMs in the constructor options), and that the txnID hasn't been used before. If you run several processes, pass { txnIdStore } with your own markUsed(txnId, keepUntilMs) backed by shared storage, such as Redis SET NX.
License
Apache-2.0
