SAML "NotOnOrAfter" clock skew assertion expired in CI
SAML assertions carry a validity window (NotBefore / NotOnOrAfter). If the runner clock is skewed from the IdP, the SP treats a valid assertion as expired or not yet valid and rejects it.
What this error means
A SAML login test fails with an error citing NotOnOrAfter or "assertion condition not met". The runner clock drifted from the IdP so the time window check fails.
Error: SAML assertion expired: clock skew too great
NotOnOrAfter: 2026-06-30T12:00:05Z now: 2026-06-30T12:00:40ZCommon causes
Runner clock skewed from the IdP
A drifted runner clock puts current time outside the assertion window, so validation fails.
A very short assertion lifetime
A tight NotOnOrAfter window can expire during a slow test before the SP validates it.
How to fix it
Allow a small acceptedClockSkew
Configure a few seconds of accepted clock skew so minor runner drift does not reject a valid assertion.
const saml = new SAML({
acceptedClockSkewMs: 30000,
idpCert: cert, issuer: 'ci-sp'
});Synchronize the runner clock
- Ensure the runner clock is set by NTP.
- Keep the mock IdP and runner on the same time source.
- Avoid artificially short assertion lifetimes in tests.
How to prevent it
- Set a small acceptedClockSkew on the SP for CI.
- Keep runner and IdP clocks NTP-synchronized.
- Avoid tiny assertion lifetimes in test fixtures.