SAML Clock Skew in Keycloak
Overview
In SAML 2.0 authentication, the Identity Provider (IdP) issues assertions that contain timestamps defining a strict validity window. The Service Provider (SP) validates these timestamps against its own system clock.
When the clocks of the IdP and SP are not perfectly synchronized — even by a few seconds — valid assertions can be rejected, causing authentication failures. This time difference is called clock skew.
Clock skew is one of the most common and frustrating issues encountered in SAML deployments. It can appear intermittently, making it difficult to diagnose, and often manifests as vague error messages like "assertion expired" or "assertion not yet valid".
How SAML timestamps work
Every SAML assertion contains a <Conditions> element with two critical attributes:
NotBefore— the assertion is not valid before this timestampNotOnOrAfter— the assertion expires at this timestamp
<saml:Conditions
NotBefore="2025-03-26T10:00:00Z"
NotOnOrAfter="2025-03-26T10:05:00Z">
...
</saml:Conditions>When the SP receives the assertion, it checks:
NotBefore ≤ current time < NotOnOrAfterIf the SP's clock is ahead or behind the IdP's clock, the SP's "current time" may fall outside this window, and the assertion is rejected.
What causes clock skew
Clock skew occurs when two servers have different system times. Common causes include:
- NTP misconfiguration — one or both servers are not synchronizing time via NTP, or are using different NTP sources
- Virtual machine clock drift — hypervisors can introduce clock drift, especially after VM suspend/resume cycles
- Container environments — containers share the host clock, but if the host drifts, all containers drift with it
- Geographic distribution — servers in different regions may sync to different NTP pools with slightly different offsets
- Cloud provider clock variance — while generally minimal, clock differences between cloud providers or regions can occur
The impact of clock skew on SAML authentication
Consider a scenario where the IdP issues an assertion at 10:00:00 with a 5-minute validity window:
Assertion valid: 10:00:00 → 10:05:00SP clock is 3 minutes ahead
The SP thinks it is 10:03:00 when the real time is 10:00:00. The assertion was just issued, but from the SP's perspective, 3 minutes have already passed. With a 5-minute window, this still works — but the margin is thin.
SP clock is 6 minutes ahead
The SP thinks it is 10:06:00. The assertion's NotOnOrAfter is 10:05:00, so the SP considers it expired and rejects it.
SP clock is 2 minutes behind
The SP thinks it is 09:58:00. The assertion's NotBefore is 10:00:00, so the SP considers it not yet valid and rejects it.
How allowedClockSkew fixes the problem
The allowedClockSkew setting (also called allowedClockDrift in some libraries) extends the assertion validity window on both sides:
Effective start = NotBefore − allowedClockSkew
Effective end = NotOnOrAfter + allowedClockSkewFor example, with a 2-minute allowed skew and the original window of 10:00:00 → 10:05:00:
Extended window: 09:58:00 → 10:07:00This gives the SP a tolerance buffer, so small clock differences do not cause failures.
Visual representation
Without allowedClockSkew:
NotBefore NotOnOrAfter
| |
──────┼────────────────────────────┼──────── time
| valid window |
With allowedClockSkew = 2 minutes:
NB − 2min NOA + 2min
| |
───┼────────────────────────────────────┼─── time
| extended valid window |Configuring allowed clock skew in Keycloak
As an Identity Provider
When Keycloak acts as the IdP, the assertion validity window is controlled by the SAML client settings. You can adjust:
- Open Keycloak Admin Console
- Navigate to Clients and select your SAML client
- Go to the Advanced tab
- Find Assertion Lifespan — this controls how long the assertion is valid (the window between
NotBeforeandNotOnOrAfter)
A longer assertion lifespan provides more tolerance for clock differences, but also increases the replay window.
TIP
A typical assertion lifespan of 5 minutes (300 seconds) is a good balance between security and usability. Very short lifespans (30-60 seconds) are more susceptible to clock skew issues.
As a Service Provider (IdP Broker)
When Keycloak acts as a Service Provider (brokering authentication from an external IdP), you can configure the allowed clock skew:
- Open Keycloak Admin Console
- Navigate to Identity Providers
- Select your SAML Identity Provider
- Scroll to Allowed clock skew
- Set the value in seconds (e.g.,
30for 30 seconds of tolerance)
WARNING
Avoid setting allowedClockSkew to very large values (e.g., more than 5 minutes). A large skew tolerance weakens replay attack protection, as expired assertions would still be accepted within the tolerance window.
Best practices
Fix the root cause first
allowedClockSkew is a safety net, not a solution. The root cause of clock skew is unsynchronized clocks. Always ensure:
- NTP is enabled on all servers involved in the SAML flow (IdP, SP, and any intermediaries)
- The same NTP source is used across all servers when possible
- NTP status is monitored — clock drift can reoccur if NTP synchronization breaks
Use a reasonable tolerance
A good allowedClockSkew value is 30 to 120 seconds. This covers:
- Minor NTP jitter (typically < 1 second)
- Network propagation delays
- Occasional NTP sync gaps
Monitor for clock skew issues
Watch for these error messages in your SP or Keycloak logs:
- "Could not validate timestamp: expired" — SP clock is ahead of IdP
- "Could not validate timestamp: not yet valid" — SP clock is behind IdP
- "A valid SubjectConfirmation was not found" — can also indicate clock skew affecting the
SubjectConfirmationDatatimestamps
If these errors appear intermittently, clock skew is the most likely cause.
Hands-on demo
We provide an interactive Docker-based demo that lets you experiment with clock skew in a real SAML flow. The demo includes a Keycloak IdP and a Flask-based SP where you can:
- Simulate clock drift by adjusting the SP's clock offset
- Configure the allowed clock skew tolerance
- See a visual timeline of assertion validity
- Observe exactly how and why authentication succeeds or fails
The demo is available at: github.com/cloud-iam/demo-saml-skew
Conclusion
Clock skew is a common but preventable cause of SAML authentication failures. By ensuring proper NTP synchronization and configuring a reasonable allowedClockSkew value, you can eliminate these issues while maintaining the security guarantees of SAML timestamp validation.
When troubleshooting SAML failures, always check the timestamps in the assertion against the SP's system clock — the answer is usually in the difference.