cloudflare/cloudflared · error
metadata JWT is more than %s in the future
Error message
metadata JWT is more than %s in the future
What it means
validateMetadataIssuedAt also rejects JWTs whose `iat` is in the future by more than metadataAllowedClockSkew. A metadata token claiming to be issued significantly after the current time is treated as invalid, protecting against tokens minted with bad clocks or forged timestamps.
Source
Thrown at token/token.go:516
_ = resp.Body.Close()
rawJWT := resp.Header.Get(accessMetadataRespHeader)
if rawJWT == "" {
return "", fmt.Errorf("failed to find Access application at %s", reqURL)
}
return rawJWT, nil
}
func validateMetadataIssuedAt(iat int64, now time.Time) error {
if iat <= 0 {
return errors.New("metadata JWT iat is missing or invalid")
}
issuedAt := time.Unix(iat, 0)
if issuedAt.Before(now.Add(-metadataMaxAge)) {
return fmt.Errorf("metadata JWT is older than %s", metadataMaxAge)
}
if issuedAt.After(now.Add(metadataAllowedClockSkew)) {
return fmt.Errorf("metadata JWT is more than %s in the future", metadataAllowedClockSkew)
}
return nil
}
func handleRedirects(req *http.Request, via []*http.Request, orgToken string) error {
// attach org token to login request
if strings.Contains(req.URL.Path, AccessLoginWorkerPath) {
req.AddCookie(&http.Cookie{Name: tokenCookie, Value: orgToken}) //nolint: gosec
}
// attach app session cookie to authorized request
if strings.Contains(req.URL.Path, AccessAuthorizedWorkerPath) {
// We need to check and see if the CF_APP_SESSION cookie was set
for _, prevReq := range via {
if prevReq != nil && prevReq.Response != nil {
for _, c := range prevReq.Response.Cookies() {
if c.Name == appSessionCookie {
req.AddCookie(&http.Cookie{Name: appSessionCookie, Value: c.Value}) //nolint: gosecView on GitHub (pinned to 2253eeeb25)
Solutions
- Synchronize the local clock with NTP (chronyd/systemd-timesyncd, `w32tm /resync` on Windows).
- For VMs/containers, enable the hypervisor/host clock-sync feature and resume-pause clock catch-up.
- Re-run the command after the clock is correct; the token itself is fine.
- Verify no test/mocked time source (e.g. faketime, frozen CLOCK_REALTIME) is in effect for the process.
Example fix
// before $ cloudflared access login https://myteam.cloudflareaccess.com // error: metadata JWT is more than 5m0s in the future // after — fix local clock, then retry $ sudo timedatectl set-ntp true && sudo chronyc makestep $ cloudflared access login https://myteam.cloudflareaccess.com
Defensive patterns
Strategy: validation
Validate before calling
// detect a lagging local clock before calling GetAppInfo
resp, err := http.Head("https://www.cloudflare.com")
if err == nil {
serverDate, _ := http.ParseTime(resp.Header.Get("Date"))
if skew := time.Since(serverDate); skew < -time.Minute {
return fmt.Errorf("local clock is %s behind server time; enable NTP", -skew)
}
} Try / catch
appInfo, err := token.GetAppInfo(authDomain, appURL)
if err != nil {
if strings.Contains(err.Error(), "in the future") {
return fmt.Errorf("%w — local clock is behind; resynchronize with NTP and retry", err)
}
return err
} Prevention
- Enable NTP/systemd-timesyncd on all machines running cloudflared.
- Enable clock sync for paused/resumed VMs and WSL instances.
- Avoid faketime or frozen-clock wrappers around cloudflared processes.
- Alert on host clock drift larger than a minute.
When it happens
Trigger: GetAppInfo parses a metadata JWT whose `iat` exceeds now + metadataAllowedClockSkew. Typically caused by the local machine's clock running behind real time (slow clock) while the edge issued the token with the correct current timestamp.
Common situations: Laptop/desktop with drifting RTC or paused VM whose clock fell behind; container with wrong timezone/clock after host suspend; NTP not running so local time lags the Cloudflare edge by minutes or hours.
Related errors
- metadata JWT is older than %s
- invalid token
- metadata JWT aud is empty
- metadata JWT iat is missing or invalid
- failed to parse auth_domain %q: %w
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/63f037e95c13604c.
Report an issue: GitHub.