diff --git a/Gotrue/User.cs b/Gotrue/User.cs
index 023fd2c..a6f2454 100644
--- a/Gotrue/User.cs
+++ b/Gotrue/User.cs
@@ -61,6 +61,9 @@ public class User
[JsonProperty("updated_at")]
public DateTime? UpdatedAt { get; set; }
+ [JsonProperty("banned_until")]
+ public DateTime? BannedUntil { get; set; }
+
[JsonProperty("is_anonymous")]
public bool IsAnonymous { get; set; }
@@ -103,6 +106,19 @@ public class AdminUserAttributes : UserAttributes
///
[JsonProperty("phone_confirm")]
public bool? PhoneConfirm { get; set; }
+
+ ///
+ /// Determines how long a user is banned for.
+ /// This property is ignored when creating a user.
+ /// If you want to create a user banned, first create the user then update it sending this property.
+ /// The format for the ban duration follows a strict sequence of decimal numbers with a unit suffix.
+ /// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
+ /// For example, some possible durations include: '300ms', '2h45m', '1200s'.
+ /// Setting the ban duration to "none" lifts the ban on the user.
+ /// Only a service role can modify.
+ ///
+ [JsonProperty("ban_duration")]
+ public string? BanDuration { get; set; }
}
///
diff --git a/GotrueExample/GotrueExample.csproj b/GotrueExample/GotrueExample.csproj
index 7436345..b43c349 100644
--- a/GotrueExample/GotrueExample.csproj
+++ b/GotrueExample/GotrueExample.csproj
@@ -2,7 +2,7 @@
Exe
- net7.0
+ net8.0
diff --git a/GotrueTests/GotrueTests.csproj b/GotrueTests/GotrueTests.csproj
index d965618..381f704 100644
--- a/GotrueTests/GotrueTests.csproj
+++ b/GotrueTests/GotrueTests.csproj
@@ -1,7 +1,7 @@
- net7.0
+ net8.0
false
diff --git a/GotrueTests/ServiceRoleTests.cs b/GotrueTests/ServiceRoleTests.cs
index 6973e49..4c0b8ca 100644
--- a/GotrueTests/ServiceRoleTests.cs
+++ b/GotrueTests/ServiceRoleTests.cs
@@ -140,6 +140,30 @@ public async Task UpdateUserById()
AreNotEqual(createdUser.Email, updatedUser.Email);
}
+ [TestMethod("Service Role: Ban User by Id")]
+ public async Task BanUserById()
+ {
+ var createdUser = await _client.CreateUser($"{RandomString(12)}@supabase.io", PASSWORD);
+
+ IsNotNull(createdUser);
+
+ int banDurationSeconds = RandomNumber();
+ DateTime bannedUntil = DateTime.UtcNow + TimeSpan.FromSeconds(banDurationSeconds);
+ var updatedUser = await _client.UpdateUserById(createdUser.Id ?? throw new InvalidOperationException(), new AdminUserAttributes { BanDuration = $"{banDurationSeconds}s" });
+
+ IsNotNull(updatedUser);
+
+ AreEqual(createdUser.Id, updatedUser.Id);
+ IsNotNull(updatedUser.BannedUntil);
+ IsTrue((updatedUser.BannedUntil.Value - bannedUntil).Duration().TotalSeconds < 1);
+
+ updatedUser = await _client.UpdateUserById(createdUser.Id ?? throw new InvalidOperationException(), new AdminUserAttributes { BanDuration = "none" });
+ IsNotNull(updatedUser);
+
+ AreEqual(createdUser.Id, updatedUser.Id);
+ IsFalse(updatedUser.BannedUntil.HasValue);
+ }
+
[TestMethod("Service Role: Delete User")]
public async Task DeletesUser()
{
diff --git a/GotrueTests/TestUtils.cs b/GotrueTests/TestUtils.cs
index d155edf..f1b40db 100644
--- a/GotrueTests/TestUtils.cs
+++ b/GotrueTests/TestUtils.cs
@@ -35,6 +35,17 @@ public static string GetRandomPhoneNumber()
return $"+1{inner}";
}
+ ///
+ /// Returns a random number within the limits specified via parameters.
+ ///
+ /// Minimum value. Default 0.
+ /// Maximum value. Default 1000.
+ /// Integer within the range.
+ public static int RandomNumber(int minValue = 0, int maxValue = 1000)
+ {
+ return Random.Next(minValue, maxValue);
+ }
+
public static string GenerateServiceRoleToken()
{
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("37c304f8-51aa-419a-a1af-06154e63707a")); // using GOTRUE_JWT_SECRET