Issue a new refresh token every time a refresh token is used (rotation); immediately invalidate the previously used refresh token upon issuing the replacement.
Group related refresh tokens into a token family by storing a shared family_id alongside each token record in your database.
On each refresh request, look up the presented refresh token; if found and valid, issue a new token, invalidate the old one, and return the new access and refresh tokens.
If the presented refresh token is not found (already rotated or deleted), check whether it belongs to a known family; if it does, this signals a reuse attack — immediately invalidate all tokens in that family and require the user to re-authenticate.
Return an appropriate error (e.g., invalid_grant) to the client when reuse is detected; do not silently ignore the event.
Log reuse detection events with client IP, user id, and token family id for security monitoring and incident response.
Known gotchas
Network failures can cause a client to re-present a legitimately rotated token (the new token was issued but the response was lost); consider a short grace window or exact-once delivery semantics to reduce false-positive reuse detection.
Storing refresh tokens as plain hashes (rather than encrypted) is sufficient for lookup but means you cannot retrieve the raw token value after storage — design your schema for hash-based lookup from the start.
RFC 9700 (OAuth 2.0 Security BCP, January 2025) treats refresh token rotation as a mandatory best practice, not optional; new implementations should enable it by default.
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp