diff --git a/src/api/SIGCM2.Domain/Exceptions/InvalidRefreshTokenException.cs b/src/api/SIGCM2.Domain/Exceptions/InvalidRefreshTokenException.cs
new file mode 100644
index 0000000..7c27a5f
--- /dev/null
+++ b/src/api/SIGCM2.Domain/Exceptions/InvalidRefreshTokenException.cs
@@ -0,0 +1,24 @@
+namespace SIGCM2.Domain.Exceptions;
+
+///
+/// Thrown when a refresh token is invalid (not found, expired, malformed, or user mismatch).
+/// Maps to HTTP 401 with a generic error message — never reveal the specific reason to the client.
+///
+public sealed class InvalidRefreshTokenException : Exception
+{
+ public InvalidRefreshTokenException(string message = "Invalid refresh token")
+ : base(message) { }
+}
+
+///
+/// Thrown when a previously-rotated (revoked) refresh token is presented again.
+/// Triggers chain revocation of the entire token family.
+/// Maps to HTTP 401 with the SAME generic message as InvalidRefreshTokenException
+/// to avoid leaking information to attackers.
+/// The backend logs distinguish between the two cases.
+///
+public sealed class TokenReuseDetectedException : Exception
+{
+ public TokenReuseDetectedException()
+ : base("Token reuse detected") { }
+}