Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,49 @@ module.exports = {
cert: String or fs.readFileSync("./your/cert/location", "utf-8"),
privateKey: fs.readFileSync("./your/private/key/location", "utf-8"),
signingCert: fs.readFileSync("./your/signing/cert/location", "utf-8"),
disableRequestedAuthnContext: true, (optional, see SAML configuration below)
wantAuthnResponseSigned: false, (optional, see SAML configuration below)
}
*/
]
};
```

## SAML configuration

A SAML provider entry accepts the following fields:

- `name`: A short identifier for the provider.
- `type`: Set to `saml`.
- `url`: The identity provider single sign-on endpoint that CryptPad redirects users to.
- `issuer`: The service provider entity identifier for this CryptPad instance.
- `cert`: The identity provider signing certificate, as a PEM string or an array of PEM strings. CryptPad uses it to verify the signature on the SAML response.
- `privateKey` and `signingCert`: An optional service provider key pair, used only when the identity provider requires CryptPad to sign its authentication requests. Most deployments omit both.
- `disableRequestedAuthnContext`: Optional. Set to `true` to stop CryptPad from requesting a specific authentication context. When unset, node-saml requests the `PasswordProtectedTransport` context.
- `wantAuthnResponseSigned`: Optional. Set to `false` to accept a signed assertion inside an unsigned response. When unset, node-saml requires the response itself to be signed.

The certificate value must be valid PEM or base64. When you paste a certificate inline, keep every line flush against the left margin, because leading whitespace from indenting the block to match the surrounding code prevents the certificate from parsing.

### Microsoft Entra ID

In the Entra enterprise application, set the Identifier (Entity ID) to the same value as the `issuer` field, for example `https://your-domain/saml/metadata`, and set the Reply URL (Assertion Consumer Service URL) to `https://your-domain/ssoauth`. Download the Base64 signing certificate from the same application and use it as the `cert` value.

Two Entra defaults commonly need attention. First, node-saml requests the `PasswordProtectedTransport` authentication context with exact matching. Entra rejects the sign-in with error AADSTS75011 when the user completes multi-factor or passwordless authentication, because the method no longer matches the requested context. Setting `disableRequestedAuthnContext: true` allows Entra to apply its own policy.

Second, Entra signs the assertion but not the response wrapper by default, while node-saml requires a signed response and otherwise returns the `Invalid document signature` error. Set the Entra Signing Option to "Sign SAML response and assertion" to keep the stronger posture, or set `wantAuthnResponseSigned: false` to accept assertion-only signing. The assertion signature stays required in both cases.

A working Entra provider entry looks like this:

```
{
name: 'entra',
type: 'saml',
url: 'https://login.microsoftonline.com/<tenant-id>/saml2',
issuer: 'https://your-domain/saml/metadata',
cert: `-----BEGIN CERTIFICATE-----
<base64 lines, flush left, no indentation>
-----END CERTIFICATE-----`,
disableRequestedAuthnContext: true,
wantAuthnResponseSigned: false,
}
```
6 changes: 4 additions & 2 deletions protocols/saml.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ module.exports = (SSOUtils) => {
issuer: cfg.issuer,
idpCert: cfg.cert,
privateKey: cfg.privateKey,
publicCert: cfg.signingCert
publicCert: cfg.signingCert,
disableRequestedAuthnContext: cfg.disableRequestedAuthnContext,
wantAuthnResponseSigned: cfg.wantAuthnResponseSigned
});
cb(void 0, saml);
};
Expand Down Expand Up @@ -61,7 +63,7 @@ module.exports = (SSOUtils) => {
idpData: {}
});
}).catch(err => {
Env.Log.error('ERROR_SAML_CALLBACK', err);
Env.Log.error('ERROR_SAML_CALLBACK', Util.serializeError(err));
return void cb('EINVAL');
});
});
Expand Down