Skip to content

Commit

Permalink
Adds support for managing user refresh-tokens and user sessions
Browse files Browse the repository at this point in the history
  • Loading branch information
kailash-b committed Oct 22, 2024
1 parent 6a7a0d1 commit bb6c6e6
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 4 deletions.
40 changes: 40 additions & 0 deletions src/Auth0.ManagementApi/Clients/IUsersClient.cs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -267,5 +271,41 @@ public interface IUsersClient
/// <param name="cancellationToken">The cancellation token to cancel operation.</param>
/// <returns>A <see cref="Task"/> that represents the asynchronous delete operation.</returns>
Task DeleteAuthenticationMethodAsync(string userId, string authenticationMethodId, CancellationToken cancellationToken = default);

/// <summary>
/// Retrieve details for a user's refresh tokens.
/// </summary>
/// <param name="request"><see cref="UserRefreshTokensGetRequest"/></param>
/// <param name="pagination"><see cref="CheckpointPaginationInfo"/></param>
/// <param name="cancellationToken"><see cref="CancellationToken"/></param>
/// <returns>Collection of <see cref="RefreshTokenInformation"/></returns>
Task<ICheckpointPagedList<RefreshTokenInformation>> GetRefreshTokensAsync(
UserRefreshTokensGetRequest request, CheckpointPaginationInfo pagination, CancellationToken cancellationToken = default);

/// <summary>
/// Delete all refresh tokens for a user.
/// </summary>
/// <param name="userId">ID of the user to remove refresh tokens for</param>
/// <param name="cancellationToken"><see cref="CancellationToken"/></param>
/// <returns></returns>
Task DeleteRefreshTokensAsync(string userId, CancellationToken cancellationToken = default);

/// <summary>
/// Retrieve details for a user's sessions.
/// </summary>
/// <param name="request"><see cref="UserSessionsGetRequest"/></param>
/// <param name="pagination"><see cref="CheckpointPaginationInfo"/></param>
/// <param name="cancellationToken"><see cref="CancellationToken"/></param>
/// <returns>Collection of <see cref="Sessions"/></returns>
Task<ICheckpointPagedList<Sessions>> GetUserSessionsAsync(
UserSessionsGetRequest request, CheckpointPaginationInfo pagination, CancellationToken cancellationToken = default);

/// <summary>
/// Delete all sessions for a user.
/// </summary>
/// <param name="userId">ID of the user to remove sessions for</param>
/// <param name="cancellationToken"><see cref="CancellationToken"/></param>
/// <returns></returns>
Task DeleteSessionsAsync(string userId, CancellationToken cancellationToken = default);
}
}
68 changes: 68 additions & 0 deletions src/Auth0.ManagementApi/Clients/UsersClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -21,6 +23,8 @@ public class UsersClient : BaseClient, IUsersClient
readonly JsonConverter[] permissionsConverters = new JsonConverter[] { new PagedListConverter<UserPermission>("permissions") };
readonly JsonConverter[] organizationsConverters = new JsonConverter[] { new PagedListConverter<Organization>("organizations") };
readonly JsonConverter[] authenticationMethodConverters = new JsonConverter[] { new PagedListConverter<AuthenticationMethod>("authenticators") };
readonly JsonConverter[] refreshTokensConverter = new JsonConverter[] { new CheckpointPagedListConverter<RefreshTokenInformation>("tokens") };
readonly JsonConverter[] sessionsConverter = new JsonConverter[] { new CheckpointPagedListConverter<Sessions>("sessions") };

/// <summary>
/// Initializes a new instance of <see cref="UsersClient"/>.
Expand Down Expand Up @@ -471,5 +475,69 @@ public Task DeleteAuthenticationMethodAsync(string userId, string authentication
{
return Connection.SendAsync<object>(HttpMethod.Delete, BuildUri($"users/{EncodePath(userId)}/authentication-methods/{EncodePath(authenticationMethodId)}"), null, DefaultHeaders, cancellationToken: cancellationToken);
}

/// <inheritdoc cref="IUsersClient.GetRefreshTokensAsync"/>
public Task<ICheckpointPagedList<RefreshTokenInformation>> 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<string, string>
{
{"from", pagination.From},
{"take", pagination.Take.ToString()},
};

return Connection.GetAsync<ICheckpointPagedList<RefreshTokenInformation>>(
BuildUri($"users/{EncodePath(request.UserId)}/refresh-tokens", queryStrings),
DefaultHeaders,
refreshTokensConverter, cancellationToken: cancellationToken);
}

/// <inheritdoc cref="IUsersClient.DeleteRefreshTokensAsync"/>
public Task DeleteRefreshTokensAsync(string userId, CancellationToken cancellationToken = default)
{
return Connection.SendAsync<object>(
HttpMethod.Delete,
BuildUri($"users/{EncodePath(userId)}/refresh-tokens"),
null,
DefaultHeaders, cancellationToken: cancellationToken);
}

/// <inheritdoc cref="IUsersClient.GetUserSessionsAsync"/>
public Task<ICheckpointPagedList<Sessions>> 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<string, string>
{
{"from", pagination.From},
{"take", pagination.Take.ToString()},
};

return Connection.GetAsync<ICheckpointPagedList<Sessions>>(
BuildUri($"users/{EncodePath(request.UserId)}/sessions", queryStrings),
DefaultHeaders,
sessionsConverter, cancellationToken: cancellationToken);
}

/// <inheritdoc cref="IUsersClient.DeleteSessionsAsync"/>
public Task DeleteSessionsAsync(string userId, CancellationToken cancellationToken = default)
{
return Connection.SendAsync<object>(
HttpMethod.Delete,
BuildUri($"users/{EncodePath(userId)}/sessions"),
null,
DefaultHeaders, cancellationToken: cancellationToken);
}
}
}
21 changes: 21 additions & 0 deletions src/Auth0.ManagementApi/Models/Users/UserRefreshTokens.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Collections.Generic;
using Auth0.ManagementApi.Models.RefreshTokens;

namespace Auth0.ManagementApi.Models.Users
{
/// <summary>
/// User's Refresh Tokens
/// </summary>
public class UserRefreshTokens
{
/// <summary>
/// List of <see cref="RefreshTokenInformation"/>
/// </summary>
public IList<RefreshTokenInformation> Tokens { get; set; }

/// <summary>
/// The maximum token ID of the current result set, to be used as the "from" query parameter for the next call.
/// </summary>
public string Next { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Auth0.ManagementApi.Models.Users
{
/// <summary>
/// Represents the information required to Get User Refresh Tokens
/// </summary>
public class UserRefreshTokensGetRequest
{
/// <summary>
/// Id of the user to get refresh tokens for
/// </summary>
public string UserId { get; set; }
}
}
13 changes: 13 additions & 0 deletions src/Auth0.ManagementApi/Models/Users/UserSessionsGetRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Auth0.ManagementApi.Models.Users
{
/// <summary>
/// Represents the information required to Get User's sessions
/// </summary>
public class UserSessionsGetRequest
{
/// <summary>
/// Id of the user to get sessions for
/// </summary>
public string UserId { get; set; }
}
}
40 changes: 36 additions & 4 deletions tests/Auth0.ManagementApi.IntegrationTests/UsersTests.cs
Original file line number Diff line number Diff line change
@@ -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
{
Expand Down Expand Up @@ -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<ICheckpointPagedList<RefreshTokenInformation>>(
sampleGetRefreshTokensResponse,
new JsonConverter[] { new CheckpointPagedListConverter<RefreshTokenInformation>("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<ICheckpointPagedList<Sessions>>(
sampleSessionResponse,
new JsonConverter[] { new CheckpointPagedListConverter<Sessions>("sessions") });

sessions.Should().NotBeNull();
sessions.Count.Should().Be(2);
}

private class CustomMetadata
{
public string Name { get; set; }
Expand Down

0 comments on commit bb6c6e6

Please sign in to comment.