SAML 2.0 & 1.1 Assertion Parser & Validator
=============
boxyhq/saml20 is a fork of a fork of saml20. It now has extended functionality and diverges from the original unmaintained library. The new package is published here - https://www.npmjs.com/package/@boxyhq/saml20
$ npm install @boxyhq/saml20parse() and validate() return promises. Before 1.6.0 they took a callback as their last argument; since 1.6.0 a callback is ignored and is never called, so await the result or use .then()/.catch() instead.
Verifies a SAML Response (or a lone Assertion) and resolves with the user's profile. It rejects when anything fails: an unsuccessful StatusCode, a missing or invalid signature, an expired assertion, or a failed audience, InResponseTo, Recipient or replay check.
rawResponse is the XML as a string (decode the base64 SAMLResponse form field first).
options (TypeScript: ValidateOptions):
publicKey: the trusted IdP signing certificate, as base64 DER or PEM. Several certificates (for key rotation) are separated by commas.thumbprint: the SHA-1 thumbprint(s) of a trusted certificate, comma-separated. The certificate itself is taken from theKeyInfoof the signature being verified. Pass eitherpublicKeyorthumbprint, not both.privateKey(optional): decrypts anEncryptedAssertion.audience(optional): the expected audience, or a list of accepted ones. When set, everyAudienceRestrictionin the assertion must name one of them.strictAudienceValidation(optional): require an exact audience match. Without it, an audience that merely starts with the expected value is accepted.inResponseTo(optional): the ID of theAuthnRequestthis response answers. When set, the signed content must carry the sameInResponseTo; a missing value fails. Fails withInvalid InResponseTo.recipient(optional). The ACS URL the response was posted to. When set, the signed content must name it: a signedResponse/@Destinationmust equal it, when any bearerSubjectConfirmationDatacarries aRecipient, one bearer confirmation must both name it and be within its ownNotBefore/NotOnOrAfterwindow (soNotOnOrAfteris required on it;bypassExpirationskips this window check but not theRecipientmatch), and at least one of the two must be present. An emptyRecipientcounts as present and never matches. The unsignedResponsewrapper is never used. Fails withInvalid Recipient.assertionReplayValidator(optional):(info) => boolean | Promise<boolean>, called after every other check passes, with{ assertionId, sessionIndex, notOnOrAfter, inResponseTo }from the signed assertion. Returntrueif the assertion was already used, and the response is rejected as a replay. Keep each entry until at leastnotOnOrAfterplus 10 minutes, the clock skewvalidate()allows.bypassExpiration(optional). This flag indicates expiration validation bypass (useful for testing, not recommended in production environments);allowedSignatureAlgorithms/allowedHashAlgorithms(optional). Algorithm allowlists forwarded tovalidateSignature, see below.maxSignatureReferences(optional). Ceiling onSignedInfo/Referenceelements, forwarded tovalidateSignature, see below.
const saml = require('@boxyhq/saml20').default;
const profile = await saml.validate(rawResponse, {
publicKey: 'MIICDzCCAXygAwIBAgIQVWXAvbbQyI5Bc...',
audience: 'https://sp.example.com',
strictAudienceValidation: true,
inResponseTo: requestId,
recipient: 'https://sp.example.com/acs',
});
const { claims, issuer, sessionIndex, assertionId, notOnOrAfter } = profile;Errors are Errors with a fixed message. When the cause is more specific (for example, why a signature failed), the error is a WrapError and the cause is in error.inner.
Returns the Issuer of a SAML Response without validating anything. Use it to find out which IdP a response claims to come from, so you can pick the certificate to pass to validate().
const issuer = saml.parseIssuer(rawResponse);Resolves with the same profile as validate(), but checks nothing: not the signature, expiry, audience or anything else. Anyone can forge its output, so never use it to authenticate a user. Use validate() for that, and parseIssuer() to read the Issuer before validating.
Verifies the XML signature on xml and returns the signed XML, or throws / returns null when the signature is invalid. Pass either publicKey (one certificate, or several separated by commas for key rotation) or thumbprint, not both.
options (optional) restricts which algorithms are accepted:
allowedSignatureAlgorithms— acceptedSignatureMethodURIs.allowedHashAlgorithms— acceptedDigestMethodURIs.
When an allowlist is omitted, the default set from xml-crypto applies (RSA-SHA1, RSA-SHA256, RSA-SHA512 and SHA-1, SHA-256, SHA-512 digests). When one is given, a document using any other algorithm is rejected; an empty list rejects everything.
maxSignatureReferences— maximum number ofReferenceelements accepted in the signature'sSignedInfo(default 16). A SAML signature carries exactly one. The ceiling bounds the workxml-cryptodoes before it verifiesSignatureValue: every Reference is canonicalized first, so an unbounded list is an unauthenticated CPU denial of service. A document over the ceiling is rejected withinvalid signature: SignedInfo declares N References; at most M are allowed, before any canonicalization.
var saml = require('@boxyhq/saml20').default;
var signedXml = saml.validateSignature(xml, publicKey, null, {
allowedSignatureAlgorithms: [
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512',
],
allowedHashAlgorithms: [
'http://www.w3.org/2001/04/xmlenc#sha256',
'http://www.w3.org/2001/04/xmlenc#sha512',
],
});$ npm test # mocha with coverage
$ npm run typecheck # type-checks lib/ and test/
$ npm run lintFixtures live in test/assets. Tests that need a fresh validity window, or a shape the fixtures do not have, build and sign their own documents with the helpers in test/helpers/fixtures.ts.
Thanks for taking the time to contribute! Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make will benefit everybody and are appreciated.
Please try to create bug reports that are:
- Reproducible. Include steps to reproduce the problem.
- Specific. Include as much detail as possible: which version, what environment, etc.
- Unique. Do not duplicate existing opened issues.
- Scoped to a Single Bug. One bug per report.
MIT