ory/hydra · error

Token is not valid yet

Error message

Token is not valid yet

What it means

This error is raised by fosite's jwt claims validation when `VerifyNotBefore(now, false)` fails, i.e. the token's `nbf` (not-before) claim lies in the future. The token is structurally fine but its validity window has not opened yet. The library enforces `nbf` to honor the issuer's declared start of validity.

Source

Thrown at fosite/token/jwt/map_claims.go:125

// There is no accounting for clock skew.
// As well, if any of the above claims are not in the token, it will still
// be considered a valid claim.
func (m MapClaims) Valid() error {
	vErr := new(ValidationError)
	now := TimeFunc().Unix()

	if !m.VerifyExpiresAt(now, false) {
		vErr.Inner = errors.New("Token is expired")
		vErr.Errors |= ValidationErrorExpired
	}

	if !m.VerifyIssuedAt(now, false) {
		vErr.Inner = errors.New("Token used before issued")
		vErr.Errors |= ValidationErrorIssuedAt
	}

	if !m.VerifyNotBefore(now, false) {
		vErr.Inner = errors.New("Token is not valid yet")
		vErr.Errors |= ValidationErrorNotValidYet
	}

	if vErr.valid() {
		return nil
	}

	return vErr
}

func (m MapClaims) UnmarshalJSON(b []byte) error {
	// This custom unmarshal allows to configure the
	// go-jose decoding settings since there is no other way
	// see https://github.com/square/go-jose/issues/353.
	// If issue is closed with a better solution
	// this custom Unmarshal method can be removed
	d := jjson.NewDecoder(bytes.NewReader(b))
	mp := map[string]interface{}(m)

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Sync clocks (NTP) between issuer and verifier.
  2. Wait until the token's `nbf` time passes, or re-request a token now.
  3. Fix token generation so `nbf` is set to now (or omitted).
  4. Use leeway in validation (allow a small skew margin before rejecting).

Example fix

// before
nbf := time.Now().Add(24 * time.Hour).Unix() // wrong: validity starts tomorrow
claims.Set("nbf", nbf)
// after
claims.Set("nbf", time.Now().Unix())
Defensive patterns

Strategy: validation

Validate before calling

// check nbf before use
func notBeforePassed(claims jwt.MapClaims, leeway time.Duration) bool {
    nbf, ok := claims["nbf"].(float64)
    return !ok || time.Now().Add(leeway).After(time.Unix(int64(nbf), 0))
}

Try / catch

// detect not-valid-yet specifically and retry later
var vErr *jwt.ValidationError
if errors.As(err, &vErr) && vErr.Errors&jwt.ValidationErrorNotValidYet != 0 {
    return retryAfter(nbfTime.Sub(time.Now()) + leeway)
}

Prevention

When it happens

Trigger: Parsing (via ParseWithClaims -> claims.Valid()) a JWT whose `nbf` claim is greater than the current verifier time — e.g. a token minted with a future `nbf`, or verifier clock behind issuer clock.

Common situations: Clock skew between services; tokens minted with `nbf` computed in the wrong timezone or with seconds-vs-milliseconds confusion; long-lived pre-provisioned tokens with a future start date; test tokens hand-built with an erroneous `nbf`.

Related errors


AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03). Data as JSON: /api/errors/a681be33ab795351. Report an issue: GitHub.