Skip to content
Latchkey

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.

node-saml
Error: SAML assertion expired: clock skew too great
  NotOnOrAfter: 2026-06-30T12:00:05Z  now: 2026-06-30T12:00:40Z

Common 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.

test.js
const saml = new SAML({
  acceptedClockSkewMs: 30000,
  idpCert: cert, issuer: 'ci-sp'
});

Synchronize the runner clock

  1. Ensure the runner clock is set by NTP.
  2. Keep the mock IdP and runner on the same time source.
  3. 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.

Frequently asked questions

What causes ""SubjectConfirmation ... NotOnOrAfter""?
A drifted runner clock puts current time outside the assertion window, so validation fails.
How do I fix "SubjectConfirmation ... NotOnOrAfter"?
Configure a few seconds of accepted clock skew so minor runner drift does not reject a valid assertion.

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card