diff --git a/src/Auth0.ManagementApi/Clients/IUsersClient.cs b/src/Auth0.ManagementApi/Clients/IUsersClient.cs index b29235de..1d446a45 100644 --- a/src/Auth0.ManagementApi/Clients/IUsersClient.cs +++ b/src/Auth0.ManagementApi/Clients/IUsersClient.cs @@ -1,9 +1,13 @@ + + namespace Auth0.ManagementApi.Clients { using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Auth0.ManagementApi.Models.Users; + using Auth0.ManagementApi.Models.RefreshTokens; + using Auth0.ManagementApi.Models.Sessions; using Models; using Paging; @@ -267,5 +271,41 @@ public interface IUsersClient /// The cancellation token to cancel operation. /// A that represents the asynchronous delete operation. Task DeleteAuthenticationMethodAsync(string userId, string authenticationMethodId, CancellationToken cancellationToken = default); + + /// + /// Retrieve details for a user's refresh tokens. + /// + /// + /// + /// + /// Collection of + Task> GetRefreshTokensAsync( + UserRefreshTokensGetRequest request, CheckpointPaginationInfo pagination, CancellationToken cancellationToken = default); + + /// + /// Delete all refresh tokens for a user. + /// + /// ID of the user to remove refresh tokens for + /// + /// + Task DeleteRefreshTokensAsync(string userId, CancellationToken cancellationToken = default); + + /// + /// Retrieve details for a user's sessions. + /// + /// + /// + /// + /// Collection of + Task> GetUserSessionsAsync( + UserSessionsGetRequest request, CheckpointPaginationInfo pagination, CancellationToken cancellationToken = default); + + /// + /// Delete all sessions for a user. + /// + /// ID of the user to remove sessions for + /// + /// + Task DeleteSessionsAsync(string userId, CancellationToken cancellationToken = default); } } diff --git a/src/Auth0.ManagementApi/Clients/UsersClient.cs b/src/Auth0.ManagementApi/Clients/UsersClient.cs index c381a124..06e4fb34 100644 --- a/src/Auth0.ManagementApi/Clients/UsersClient.cs +++ b/src/Auth0.ManagementApi/Clients/UsersClient.cs @@ -7,6 +7,8 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Auth0.ManagementApi.Models.RefreshTokens; +using Auth0.ManagementApi.Models.Sessions; namespace Auth0.ManagementApi.Clients { @@ -21,6 +23,8 @@ public class UsersClient : BaseClient, IUsersClient readonly JsonConverter[] permissionsConverters = new JsonConverter[] { new PagedListConverter("permissions") }; readonly JsonConverter[] organizationsConverters = new JsonConverter[] { new PagedListConverter("organizations") }; readonly JsonConverter[] authenticationMethodConverters = new JsonConverter[] { new PagedListConverter("authenticators") }; + readonly JsonConverter[] refreshTokensConverter = new JsonConverter[] { new CheckpointPagedListConverter("tokens") }; + readonly JsonConverter[] sessionsConverter = new JsonConverter[] { new CheckpointPagedListConverter("sessions") }; /// /// Initializes a new instance of . @@ -471,5 +475,69 @@ public Task DeleteAuthenticationMethodAsync(string userId, string authentication { return Connection.SendAsync(HttpMethod.Delete, BuildUri($"users/{EncodePath(userId)}/authentication-methods/{EncodePath(authenticationMethodId)}"), null, DefaultHeaders, cancellationToken: cancellationToken); } + + /// + public Task> GetRefreshTokensAsync(UserRefreshTokensGetRequest request, CheckpointPaginationInfo pagination, CancellationToken cancellationToken = default) + { + if (request == null) + throw new ArgumentNullException(nameof(request)); + + if(string.IsNullOrEmpty(request.UserId)) + throw new ArgumentException("Value cannot be null or empty.", nameof(request.UserId)); + + var queryStrings = new Dictionary + { + {"from", pagination.From}, + {"take", pagination.Take.ToString()}, + }; + + return Connection.GetAsync>( + BuildUri($"users/{EncodePath(request.UserId)}/refresh-tokens", queryStrings), + DefaultHeaders, + refreshTokensConverter, cancellationToken: cancellationToken); + } + + /// + public Task DeleteRefreshTokensAsync(string userId, CancellationToken cancellationToken = default) + { + return Connection.SendAsync( + HttpMethod.Delete, + BuildUri($"users/{EncodePath(userId)}/refresh-tokens"), + null, + DefaultHeaders, cancellationToken: cancellationToken); + } + + /// + public Task> GetUserSessionsAsync( + UserSessionsGetRequest request, CheckpointPaginationInfo pagination, + CancellationToken cancellationToken = default) + { + if (request == null) + throw new ArgumentNullException(nameof(request)); + + if(string.IsNullOrEmpty(request.UserId)) + throw new ArgumentException("Value cannot be null or empty.", nameof(request.UserId)); + + var queryStrings = new Dictionary + { + {"from", pagination.From}, + {"take", pagination.Take.ToString()}, + }; + + return Connection.GetAsync>( + BuildUri($"users/{EncodePath(request.UserId)}/sessions", queryStrings), + DefaultHeaders, + sessionsConverter, cancellationToken: cancellationToken); + } + + /// + public Task DeleteSessionsAsync(string userId, CancellationToken cancellationToken = default) + { + return Connection.SendAsync( + HttpMethod.Delete, + BuildUri($"users/{EncodePath(userId)}/sessions"), + null, + DefaultHeaders, cancellationToken: cancellationToken); + } } } diff --git a/src/Auth0.ManagementApi/Models/Users/UserRefreshTokens.cs b/src/Auth0.ManagementApi/Models/Users/UserRefreshTokens.cs new file mode 100644 index 00000000..29bb8fd3 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Users/UserRefreshTokens.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Auth0.ManagementApi.Models.RefreshTokens; + +namespace Auth0.ManagementApi.Models.Users +{ + /// + /// User's Refresh Tokens + /// + public class UserRefreshTokens + { + /// + /// List of + /// + public IList Tokens { get; set; } + + /// + /// The maximum token ID of the current result set, to be used as the "from" query parameter for the next call. + /// + public string Next { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Users/UserRefreshTokensGetRequest.cs b/src/Auth0.ManagementApi/Models/Users/UserRefreshTokensGetRequest.cs new file mode 100644 index 00000000..a50bd227 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Users/UserRefreshTokensGetRequest.cs @@ -0,0 +1,13 @@ +namespace Auth0.ManagementApi.Models.Users +{ + /// + /// Represents the information required to Get User Refresh Tokens + /// + public class UserRefreshTokensGetRequest + { + /// + /// Id of the user to get refresh tokens for + /// + public string UserId { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Users/UserSessionsGetRequest.cs b/src/Auth0.ManagementApi/Models/Users/UserSessionsGetRequest.cs new file mode 100644 index 00000000..593eba1c --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Users/UserSessionsGetRequest.cs @@ -0,0 +1,13 @@ +namespace Auth0.ManagementApi.Models.Users +{ + /// + /// Represents the information required to Get User's sessions + /// + public class UserSessionsGetRequest + { + /// + /// Id of the user to get sessions for + /// + public string UserId { get; set; } + } +} \ No newline at end of file diff --git a/tests/Auth0.ManagementApi.IntegrationTests/UsersTests.cs b/tests/Auth0.ManagementApi.IntegrationTests/UsersTests.cs index 01a3480a..4ea2187f 100644 --- a/tests/Auth0.ManagementApi.IntegrationTests/UsersTests.cs +++ b/tests/Auth0.ManagementApi.IntegrationTests/UsersTests.cs @@ -1,16 +1,22 @@ using System; using System.Dynamic; using System.Threading.Tasks; -using Auth0.Core.Exceptions; -using Auth0.ManagementApi.Models; +using System.Linq; +using System.Collections.Generic; +using System.IO; + +using Newtonsoft.Json; using FluentAssertions; using Xunit; + +using Auth0.Core.Exceptions; +using Auth0.ManagementApi.Models; using Auth0.Tests.Shared; -using System.Linq; using Auth0.ManagementApi.Paging; -using System.Collections.Generic; using Auth0.IntegrationTests.Shared.CleanUp; using Auth0.ManagementApi.IntegrationTests.Testing; +using Auth0.ManagementApi.Models.RefreshTokens; +using Auth0.ManagementApi.Models.Sessions; namespace Auth0.ManagementApi.IntegrationTests { @@ -659,6 +665,32 @@ public async Task Test_authentication_methods_crud() allAuthenticationMethods3.Count.Should().Be(0); } + [Fact] + public async void Test_get_user_refresh_tokens() + { + var sampleGetRefreshTokensResponse = await File.ReadAllTextAsync("./Data/UserGetRefreshTokensResponse.json"); + var httpClientManagementConnection = new HttpClientManagementConnection(); + var refreshTokens = httpClientManagementConnection.DeserializeContent>( + sampleGetRefreshTokensResponse, + new JsonConverter[] { new CheckpointPagedListConverter("tokens") }); + + refreshTokens.Should().NotBeNull(); + refreshTokens.Count.Should().Be(2); + } + + [Fact] + public async void Test_get_user_sessions() + { + var sampleSessionResponse = await File.ReadAllTextAsync("./Data/UserGetSessionsResponse.json"); + var httpClientManagementConnection = new HttpClientManagementConnection(); + var sessions = httpClientManagementConnection.DeserializeContent>( + sampleSessionResponse, + new JsonConverter[] { new CheckpointPagedListConverter("sessions") }); + + sessions.Should().NotBeNull(); + sessions.Count.Should().Be(2); + } + private class CustomMetadata { public string Name { get; set; }