{"record":{"id":"b65a90ab269ae355","repo":"go-kit/kit","slug":"token-is-not-valid-yet","errorCode":null,"errorMessage":"token is not valid yet","messagePattern":"token is not valid yet","errorType":"exception","errorClass":"ErrTokenNotActive","httpStatus":401,"severity":"warning","filePath":"auth/jwt/middleware.go","lineNumber":43,"sourceCode":")\n\nvar (\n\t// ErrTokenContextMissing denotes a token was not passed into the parsing\n\t// middleware's context.\n\tErrTokenContextMissing = errors.New(\"token up for parsing was not passed through the context\")\n\n\t// ErrTokenInvalid denotes a token was not able to be validated.\n\tErrTokenInvalid = errors.New(\"JWT was invalid\")\n\n\t// ErrTokenExpired denotes a token's expire header (exp) has since passed.\n\tErrTokenExpired = errors.New(\"JWT is expired\")\n\n\t// ErrTokenMalformed denotes a token was not formatted as a JWT.\n\tErrTokenMalformed = errors.New(\"JWT is malformed\")\n\n\t// ErrTokenNotActive denotes a token's not before header (nbf) is in the\n\t// future.\n\tErrTokenNotActive = errors.New(\"token is not valid yet\")\n\n\t// ErrUnexpectedSigningMethod denotes a token was signed with an unexpected\n\t// signing method.\n\tErrUnexpectedSigningMethod = errors.New(\"unexpected signing method\")\n)\n\n// NewSigner creates a new JWT generating middleware, specifying key ID,\n// signing string, signing method and the claims you would like it to contain.\n// Tokens are signed with a Key ID header (kid) which is useful for determining\n// the key to use for parsing. Particularly useful for clients.\nfunc NewSigner(kid string, key []byte, method jwt.SigningMethod, claims jwt.Claims) endpoint.Middleware {\n\treturn func(next endpoint.Endpoint) endpoint.Endpoint {\n\t\treturn func(ctx context.Context, request interface{}) (response interface{}, err error) {\n\t\t\ttoken := jwt.NewWithClaims(method, claims)\n\t\t\ttoken.Header[\"kid\"] = kid\n\n\t\t\t// Sign and get the complete encoded token as a string using the secret\n\t\t\ttokenString, err := token.SignedString(key)","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/go-kit/kit/blob/78fbbceece7bbcf073bee814a7772f4397ea756c/auth/jwt/middleware.go#L25-L61","documentation":"Returned by jwt.NewParser when the underlying jwt.ValidationError has the ValidationErrorNotValidYet bit set: the token's nbf (not before) claim is in the future. The token is well-formed and correctly signed but is not yet within its validity window, so the server refuses it.","triggerScenarios":"Clock skew: the verifying server's clock lags behind the issuing server, so a token with nbf=now appears 'not valid yet'; signer deliberately sets nbf in the future; tokens minted with nbf computed in the wrong unit (milliseconds) so it lands far ahead; tokens generated on a host with a wrong system clock.","commonSituations":"Container/VM clock drift in clusters; multi-region deployments where issuer and verifier disagree on time; switching identity providers that populate nbf differently; CI environments with frozen/skewed clocks.","solutions":["Sync clocks on all signing and verifying hosts (NTP/chrony)","Set nbf at (or slightly before) issuance — e.g. time.Now().Add(-30*time.Second) — instead of in the future","If skew is unavoidable, tolerate it by validating with leeway on the golang-jwt validator instead of relying on the strict default","Retry the request after (nbf - now) seconds once clocks are correct"],"exampleFix":"// before: nbf pushed into the future, verifier clock slightly behind\nclaims := &jwt.RegisteredClaims{NotBefore: jwt.NewNumericDate(time.Now().Add(2 * time.Minute))}\n\n// after: nbf at issuance minus small skew allowance\nclaims := &jwt.RegisteredClaims{NotBefore: jwt.NewNumericDate(time.Now().Add(-30 * time.Second))}","handlingStrategy":"retry","validationCode":"null","typeGuard":"null","tryCatchPattern":"resp, err := ep(ctx, req)\nif err != nil && errors.Is(err, jwt.ErrTokenNotActive) {\n\t// transient skew: wait briefly and retry once; if it persists, alert on clock sync\n\ttime.Sleep(2 * time.Second)\n\tresp, err = ep(ctx, req)\n}","preventionTips":["Set nbf slightly in the past (e.g. now-30s) to absorb normal skew","Keep signer and verifier clocks NTP-synced; alert on measurable drift","Prefer golang-jwt validator leeway over disabling nbf entirely"],"tags":["go","go-kit","jwt","authentication","clock-skew","nbf"],"backgroundTag":null,"analyzedSha":"78fbbceece7bbcf073bee814a7772f4397ea756c","analyzedAt":"2026-08-15T22:31:35.570Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}