{"record":{"id":"0c80deea53677dbc","repo":"SigNoz/signoz","slug":"errcodetokenrotationrequired","errorCode":"ErrCodeTokenRotationRequired","errorMessage":"token needs to be rotated","messagePattern":"token needs to be rotated","errorType":"error_code","errorClass":"errors SigNozError","httpStatus":401,"severity":"error","filePath":"pkg/types/authtypes/token.go","lineNumber":154,"sourceCode":"}\n\nfunc (typ *Token) IsExpired(idleDuration time.Duration, maxDuration time.Duration) error {\n\t// If now - last_seen_at > idle_duration, the token will be considered as expired.\n\tif !typ.LastObservedAt.IsZero() && typ.LastObservedAt.Before(time.Now().Add(-idleDuration)) {\n\t\treturn errors.New(errors.TypeUnauthenticated, ErrCodeTokenExpired, \"token has not been used for too long\")\n\t}\n\n\t// If now - created_at > max_duration, the token will be considered as expired.\n\tif typ.CreatedAt.Before(time.Now().Add(-maxDuration)) {\n\t\treturn errors.New(errors.TypeUnauthenticated, ErrCodeTokenExpired, \"token was created a long time ago\")\n\t}\n\n\treturn nil\n}\n\nfunc (typ *Token) IsRotationRequired(rotationInterval time.Duration) error {\n\tif !typ.RotatedAt.IsZero() && typ.RotatedAt.Before(time.Now().Add(-rotationInterval)) {\n\t\treturn errors.New(errors.TypeUnauthenticated, ErrCodeTokenRotationRequired, \"token needs to be rotated\")\n\t}\n\n\tif typ.RotatedAt.IsZero() && typ.CreatedAt.Before(time.Now().Add(-rotationInterval)) {\n\t\treturn errors.New(errors.TypeUnauthenticated, ErrCodeTokenRotationRequired, \"token needs to be rotated\")\n\t}\n\n\treturn nil\n}\n\nfunc (typ *Token) Rotate(accessTokenOrPrevAccessToken string, refreshTokenOrPrevRefreshToken string, rotationDuration time.Duration, idleDuration time.Duration, maxDuration time.Duration) error {\n\tif typ.PrevAccessToken == accessTokenOrPrevAccessToken && typ.PrevRefreshToken == refreshTokenOrPrevRefreshToken {\n\t\t// If the token has been rotated within the rotation duration, do nothing and return the same token.\n\t\tif !typ.RotatedAt.IsZero() && typ.RotatedAt.Before(time.Now().Add(-rotationDuration)) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn errors.New(errors.TypeUnauthenticated, errors.CodeUnauthenticated, \"invalid token pair\")\n\t}","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/SigNoz/signoz/blob/5069bf80b08f1f00d7e014eccc09902f9871004f/pkg/types/authtypes/token.go#L136-L172","documentation":"Returned by Token.IsRotationRequired when RotatedAt is set but older than the rotation interval: the token was rotated before but is due again. Enforces periodic credential rotation.","triggerScenarios":"Calling IsValid on a token whose rotatedAt is older than now minus rotationInterval.","commonSituations":"Client keeps using an access/refresh token pair past the rotation window without calling the rotate endpoint.","solutions":["Call the rotate endpoint with the current token pair to get a rotated token","Schedule rotation at intervals shorter than rotationInterval","Update SDK/client that caches tokens without rotating them"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if !tok.RotatedAt.IsZero() && time.Since(tok.RotatedAt) > rotationInterval { /* rotate now */ }","typeGuard":null,"tryCatchPattern":"if err := tok.IsRotationRequired(interval); err != nil { /* call rotate endpoint with current pair, then retry original call */ }","preventionTips":["Rotate proactively on a timer below the interval","Wrap API clients with automatic rotate-and-retry"],"tags":["tokens","auth","rotation","security-policy"],"backgroundTag":"token-rotation-required","analyzedSha":"5069bf80b08f1f00d7e014eccc09902f9871004f","analyzedAt":"2026-08-28T06:22:12.824Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}