wsfed-caep-nodejs
A WS-Federation relying party for server-side Node.js applications: the traditional web application that renders its pages on the server and keeps its session there. It covers:
- The passive requestor profile of WS-Federation 1.2:
wsignin1.0(withwfresh,wauth,whr), the response POSTed to the reply URL,wsignout1.0andwsignoutcleanup1.0. - SAML 2.0 assertions, asked for with a
wreqRequestSecurityToken, in either WS-Trust shape (February 2005, or 1.3 in a collection). A SAML 1.1 token is refused. - Strict validation: the assertion’s signature always required, verified only against the identity provider’s metadata certificates and read from what was signed (no signature wrapping); audience, recipient, time window,
wctxcorrelation, and each assertion accepted once. - Encryption:
EncryptedAssertion, AD FS’s bareEncryptedData,EncryptedIDandEncryptedAttributedecrypted withnode:crypto(AES-GCM/CBC, RSA-OAEP; PKCS#1 v1.5 refused). - Federation metadata both ways: this relying party’s written from its configuration, the identity provider’s read from a file or a URL.
- CAEP and RISC: an OpenID Shared Signals receiver that ends the application’s sessions when the identity provider revokes a session or disables an account, whether or not the browser is open.
It is TypeScript and works from JavaScript, needs no web framework, and depends on xml-crypto and @xmldom/xmldom only. It is built and tested against iya-sts’s WS-Federation identity provider.
Install
npm install wsfed-caep-nodejs
Where to read
- Server-side guide: configuration, registration, the login route, the reply URL, sign-out and the session, step by step.
- Handling CAEP and RISC events: every CAEP and RISC event type, what it carries, what the receiver does by default, and a handler for each.
- Configuration and API reference: every setting, the protocol, what is checked, encryption, errors and the API.
- TypeScript API (TypeDoc), generated from the source.
- Setting up iya-sts: registering the relying party, and reading iya-sts’s federation metadata into the library.
- Running the demo: a complete application in one container.
- Development and releases: tests, CI, branches and versions.
Quick look
import { RelyingParty } from 'wsfed-caep-nodejs';
const rp = await RelyingParty.fromFile('wsfed.json');
// /login
const request = rp.login({ relayState: '/' }); // keep request.id with the browser
// redirect to request.url
// POST /wsfed (the reply URL)
const who = await rp.handleReply({ method, url, body }, { requestId });
console.log(who.nameId, who.attributes, who.sessionIndex);
From JavaScript: const { RelyingParty } = require('wsfed-caep-nodejs'), or the same import.
The configuration is three lines:
{
"realm": "https://app.example.com/",
"replyUrl": "https://app.example.com/wsfed",
"idpMetadata": "https://idp.example.com/FederationMetadata/2007-06/FederationMetadata.xml"
}