# samlify wants you to choose a schema validator before it will do anything else

> samlify is a MIT licensed TypeScript library for SAML 2.0 single sign on in Node.js, and its most opinionated design choice is that the schema validator is yours to pick, from one of the published modules to a hand-written function, with suppression available if you accept the risk. The rest is a small dependency surface and a test suite that runs on vitest.

**tngan/samlify** — Node.js library for SAML SSO

- Repository: https://github.com/tngan/samlify
- Website: https://samlify.js.org
- Stars: 662 · Forks: 236
- Language: TypeScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/tngan-samlify

## setSchemaValidator is the first call, not an optional extra

samlify is described as a highly configurable Node.js SAML 2.0 library for single sign on, and the configuration starts with validation. The library supports multiple schema validators, with a couple of validator modules available and the option to create your own, and the documentation is emphatic that it is essential to utilize the setSchemaValidator function at the outset to avoid errors.

The published module is imported and installed in one step:

```js
import * as samlify from 'samlify';
import * as validator from '@authenio/samlify-xsd-schema-validator';
// import * as validator from '@authenio/samlify-validate-with-xmllint';
// import * as validator from '@authenio/samlify-node-xmllint';

samlify.setSchemaValidator(validator);
```

The two commented lines show the alternatives the project ships: an xmllint based validator and a node-xmllint one, alongside the XSD schema validator. That choice is not cosmetic, because the validators differ in what they need on the machine. The xmllint based ones call out to a native binary, while the XSD schema validator is a pure JavaScript module, and the tradeoff is between a validator that needs a system dependency and one that does not.

For a JavaScript project the entry point is a plain require:

```javascript
const saml = require('samlify');
```

and the full documentation lives at samlify.js.org, with a starter repository, samlify-starter, for getting up and running.

## You can write your own validator, and you can suppress validation entirely

The validator is a function, so it is yours to replace with anything that takes a response string and returns a promise:

```typescript
samlify.setSchemaValidator({
  validate: (response: string) => {
    /* implment your own or always returns a resolved promise to skip */
    return Promise.resolve('skipped');
  }
});
```

The comment in that snippet is the important part. A validator that always resolves, which is what the sample body does, skips validation altogether, and the documentation says so plainly: you can create your own schema validator and even suppress it, but you have to take the risk of accepting a malicious response.

That sentence deserves to be read as a security boundary rather than a footnote. XML in SAML is attacker-influenced by design, since the assertion, the signature and the response wrapper are all XML, and a parser that accepts a structurally wrong document is the entry point for a signature wrapping attack. Turning validation off does not merely weaken a check, it removes the layer that is supposed to reject a document the signature does not actually cover.

A custom validator that does real work, for example one that enforces the schema and then adds your own structural rules, is a reasonable extension. A validator that resolves without inspecting the response is a decision to accept that risk, and it should be made deliberately rather than as a debugging convenience that survives into production.

## Windows and the libxml validators need build tools installed first

There is one platform note in the installation section, and it is a practical one. For those using Windows, windows-build-tools should be installed globally before installing samlify if you are using the libxml validator:

```console
yarn global add windows-build-tools
```

The reason is that the xmllint based validators rely on a native library that has to be compiled for the platform, so a Node.js install alone is not enough on Windows. On a machine that picks the XSD schema validator instead, the native step disappears, which is one reason the pure JavaScript module is the default in the example.

The development setup is equally short. The project is developed using TypeScript and supports yarn as a package manager:

```console
yarn global add typescript
yarn
```

The repository is a modern TypeScript layout: an index.ts at the root, a src directory, an @types directory, a test directory, a docs directory, a tsconfig.json plus a separate tsconfig.typecheck.json, a vitest.config.ts, an eslint.config.mjs and a yarn.lock.

There is also a .skills directory in the tree, which is a newer convention for shipping agent-facing instructions inside a repository, and a CONTRIBUTING.md with the contribution expectations. The maintainer asks for pull requests to maintain the project, or for links to other repositories for use cases with different frameworks.

## Seven dependencies do the XML work, and the resolutions pin the rest

The dependency list is short enough to read in full, and it explains where the library sits in the XML stack. @xmldom/xmldom provides the DOM parser, xml-crypto handles the cryptographic side with its signing and verification, @authenio/xml-encryption covers encrypted assertions, and xpath and xml handle querying and escaping. node-rsa and the xml package cover the remaining key and serialisation needs.

The dependency count matters for a security component. SAML code runs on attacker-influenced input, so the fewer parsers and crypto helpers in the path, the smaller the surface you have to reason about. The trade-off is that a small surface also means fewer places to look when a vulnerability shows up in one of these packages.

The package.json also carries a resolutions block, which pins transitive versions across the tree: diff is held at 4.0.4 or newer, esbuild at 0.25.0, and the vite and vitepress versions used by the documentation toolchain are aligned at 6.4.3. Pinning transitive dependencies in a library is unusual, and it is there because the documentation build and the test runner share a vite dependency that would otherwise float.

The published package exposes the compiled build as build/index.js with type declarations at types/index.d.ts, and the files list ships the build, the types, the licence and the readme.

## The test suite copies key material into the build directory first

The scripts reveal how the project is tested, and one of them explains a step you would otherwise hit as a confusing failure. The pretest script prepares the test fixtures:

```json
    "pretest": "mkdir -p build/test && cp -a test/key test/misc build/test",
```

SAML tests need certificates and keys, and they live under test/key and test/misc. The compiled test run happens from the build directory, so the fixtures are copied there before vitest starts. A contributor who deletes the build directory and runs the tests directly will hit missing key files, and the pretest hook is what prevents that.

The test command itself runs the unit tests and then the type tests:

```json
    "test": "NODE_ENV=test vitest run && yarn test:types",
```

The type test step compiles tsconfig.typecheck.json, emits declarations from the main tsconfig and then type checks a consumer project under test/consumer-types, which is how the published typings are verified against a real consumer. That is a stronger guarantee than compiling the library alone, and it is the kind of check that catches a breaking change to a public type before it is published.

The build script runs a dependency audit before compiling, with yarn audit and tsc, and the coverage badge in the readme points at the vitest configuration. There is a .snyk file in the repository root, which is the configuration for Snyk's dependency scanning.

## Docs are VitePress, and installing the package installs a git hook

The documentation site is built with VitePress, with three scripts covering the loop:

```json
    "docs:dev": "vitepress dev docs",
    "docs:build": "vitepress build docs",
    "docs:preview": "vitepress preview docs",
```

The published site is samlify.js.org, and the same docs directory is where the API reference lives, so the documentation you read online is generated from the repository rather than maintained separately.

One script deserves a closer look before you install the package in a project:

```json
    "hooks:postinstall": "ln -sf $PWD/.pre-commit.sh $PWD/.git/hooks/pre-commit"
```

The postinstall hook links the repository's own pre-commit script into your .git/hooks directory when the package is installed as a dependency. It runs at install time, it writes into your git configuration, and it points at a file inside the installed package. That is a postinstall side effect in a security library, and while the intent here is benign, it is exactly the pattern that makes teams set ignore-scripts in their package manager, which then disables legitimate install steps for every other package too. Worth knowing before your CI runs with scripts disabled, or before you allow an install to write to your hooks directory.

Licensing is MIT, with copyright held by Tony Ngan from 2016 onwards, and the recent releases show the project is still moving, with v2.13.1 in May 2026, v2.14.0 in October and v2.15.0 on 2026-10-20, the same day as the last push to the repository.

## Conclusion

samlify is worth adopting for a Node.js service that has to speak SAML 2.0 as a service provider, especially if you want to choose the XML validation layer rather than accept whatever a framework integration hard codes, and if you can live with a library that leaves the metadata, certificate and flow details to the samlify-starter example and the documentation site. It is the wrong choice if you need a maintained, opinionated security component with no configuration decisions of your own, and it is unacceptable with validation suppressed, since the project itself warns that you then accept malicious responses. Verify first that the schema validator you install matches your runtime, that your XML parser and signature library versions are the ones the dependency list pins, and that your CI runs the type checks as well as the vitest suite.

## FAQ

### How do I set up samlify in a Node.js project?

Install the package, then call setSchemaValidator at the outset with one of the published validator modules, such as @authenio/samlify-xsd-schema-validator, or with your own validator object. The documentation says it is essential to do this at the outset to avoid errors.

### Can I skip XML schema validation in samlify?

Technically yes, by passing a validator whose validate function always resolves a promise. The documentation warns that you have to take the risk of accepting a malicious response, so treat it as a deliberate decision rather than a debugging shortcut.

### What do I need to install on Windows to use samlify?

If you use the libxml based validator, windows-build-tools has to be installed globally before installing samlify, using yarn global add windows-build-tools. The XSD schema validator has no native dependency.

### Which XML and crypto libraries does samlify depend on?

The runtime dependencies are @authenio/xml-encryption, @xmldom/xmldom, node-rsa, xml, xml-crypto, xml-escape and xpath. The package also pins transitive versions in a resolutions block, including diff and esbuild.

### How is samlify tested?

With vitest, preceded by a pretest step that copies the test/key and test/misc fixtures into the build directory, and followed by a type test that compiles the project and type checks a consumer project under test/consumer-types.

### What license is samlify released under?

MIT, with copyright held by Tony Ngan from 2016 onwards, and the current package version is 2.15.0.

## Sources

- [License: MIT](https://github.com/tngan/samlify/blob/master/LICENSE)
- [Project website](https://samlify.js.org)
- [README](https://github.com/tngan/samlify/blob/master/README.md)
- [Releases](https://github.com/tngan/samlify/releases)
- [tngan/samlify on GitHub](https://github.com/tngan/samlify)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/tngan-samlify
