diff --git a/src/Auth0.ManagementApi/Clients/IRefreshTokenClient.cs b/src/Auth0.ManagementApi/Clients/IRefreshTokenClient.cs new file mode 100644 index 00000000..1f6393c7 --- /dev/null +++ b/src/Auth0.ManagementApi/Clients/IRefreshTokenClient.cs @@ -0,0 +1,26 @@ +using System.Threading; +using System.Threading.Tasks; + +using Auth0.ManagementApi.Models.RefreshTokens; + +namespace Auth0.ManagementApi.Clients +{ + public interface IRefreshTokenClient + { + /// + /// Retrieve refresh token information. + /// + /// + /// + /// + Task GetAsync(RefreshTokenGetRequest request, CancellationToken cancellationToken = default); + + /// + /// Delete a refresh token by its Id. + /// + /// Id of the refresh token to delete. + /// + /// + Task DeleteAsync(string id, CancellationToken cancellationToken = default); + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Clients/ISessionsClient.cs b/src/Auth0.ManagementApi/Clients/ISessionsClient.cs new file mode 100644 index 00000000..5dee5159 --- /dev/null +++ b/src/Auth0.ManagementApi/Clients/ISessionsClient.cs @@ -0,0 +1,33 @@ +using System.Threading; +using System.Threading.Tasks; +using Auth0.ManagementApi.Models.Sessions; + +namespace Auth0.ManagementApi.Clients +{ + public interface ISessionsClient + { + /// + /// Retrieve session information. + /// + /// + /// + /// + Task GetAsync(SessionsGetRequest request, CancellationToken cancellationToken = default); + + /// + /// Delete a session by Id. + /// + /// Id of the session to delete. + /// + /// + Task DeleteAsync(string id, CancellationToken cancellationToken = default); + + /// + /// Revokes a session by Id and all associated refresh tokens. + /// + /// Id of the session to revoke + /// + /// + Task RevokeAsync(string id, CancellationToken cancellationToken = default); + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Clients/RefreshTokenClient.cs b/src/Auth0.ManagementApi/Clients/RefreshTokenClient.cs new file mode 100644 index 00000000..9c56ce8e --- /dev/null +++ b/src/Auth0.ManagementApi/Clients/RefreshTokenClient.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Auth0.ManagementApi.Models.RefreshTokens; + +namespace Auth0.ManagementApi.Clients +{ + + /// + public class RefreshTokenClient : BaseClient, IRefreshTokenClient + { + private const string RefreshTokensBasePath = "refresh-tokens"; + + /// + /// Initializes a new instance on + /// + /// used to make all API calls. + /// of the endpoint to use in making API calls. + /// Dictionary containing default headers included with every request this client makes. + public RefreshTokenClient(IManagementConnection connection, Uri baseUri, IDictionary defaultHeaders) + : base(connection, baseUri, defaultHeaders) + { + } + + /// + public Task GetAsync(RefreshTokenGetRequest request, CancellationToken cancellationToken = default) + { + if (request == null) + throw new ArgumentNullException(nameof(request)); + + if(string.IsNullOrEmpty(request.Id)) + throw new ArgumentException("Value cannot be null or empty.", nameof(request.Id)); + + return Connection.GetAsync( + BuildUri($"{RefreshTokensBasePath}/{EncodePath(request.Id)}"), + DefaultHeaders, cancellationToken: cancellationToken); + } + + /// + public Task DeleteAsync(string id, CancellationToken cancellationToken = default) + { + return Connection.SendAsync( + HttpMethod.Delete, + BuildUri($"{RefreshTokensBasePath}/{EncodePath(id)}"), + null, DefaultHeaders, cancellationToken: cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Clients/SessionsClient.cs b/src/Auth0.ManagementApi/Clients/SessionsClient.cs new file mode 100644 index 00000000..08af68e6 --- /dev/null +++ b/src/Auth0.ManagementApi/Clients/SessionsClient.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Auth0.ManagementApi.Models.Sessions; + +namespace Auth0.ManagementApi.Clients +{ + + /// + public class SessionsClient : BaseClient, ISessionsClient + { + private const string SessionsBasePath = "sessions"; + + /// + /// Initializes a new instance of . + /// + /// + /// + /// + public SessionsClient(IManagementConnection connection, Uri baseUri, IDictionary defaultHeaders) + : base(connection, baseUri, defaultHeaders) + { + } + + /// + public Task GetAsync(SessionsGetRequest request, CancellationToken cancellationToken = default) + { + if (request == null) + throw new ArgumentNullException(nameof(request)); + + if(string.IsNullOrEmpty(request.Id)) + throw new ArgumentException("Value cannot be null or empty.", nameof(request.Id)); + + return Connection.GetAsync( + BuildUri($"{SessionsBasePath}/{EncodePath(request.Id)}"), + DefaultHeaders, cancellationToken: cancellationToken); + } + + /// + public Task DeleteAsync(string id, CancellationToken cancellationToken = default) + { + return Connection.SendAsync( + HttpMethod.Delete, + BuildUri($"{SessionsBasePath}/{EncodePath(id)}"), + null, DefaultHeaders, cancellationToken: cancellationToken); + } + + /// + public Task RevokeAsync(string id, CancellationToken cancellationToken = default) + { + return Connection.SendAsync(HttpMethod.Post, + BuildUri($"{SessionsBasePath}/{EncodePath(id)}/revoke"), + null, + DefaultHeaders, cancellationToken: cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/IManagementApiClient.cs b/src/Auth0.ManagementApi/IManagementApiClient.cs index 76b87cd5..064220da 100644 --- a/src/Auth0.ManagementApi/IManagementApiClient.cs +++ b/src/Auth0.ManagementApi/IManagementApiClient.cs @@ -150,6 +150,16 @@ public interface IManagementApiClient : IDisposable /// Contains all the methods to call the /users endpoints. /// IUsersClient Users { get; } + + /// + /// Contains all the methods to call the /refresh-tokens endpoints. + /// + IRefreshTokenClient RefreshTokens { get; } + + /// + /// Contains all the methods to call the /sessions endpoints. + /// + ISessionsClient Sessions { get; } /// /// Update the Access Token used with every request. diff --git a/src/Auth0.ManagementApi/ManagementApiClient.cs b/src/Auth0.ManagementApi/ManagementApiClient.cs index 72f9ed06..fb49b109 100644 --- a/src/Auth0.ManagementApi/ManagementApiClient.cs +++ b/src/Auth0.ManagementApi/ManagementApiClient.cs @@ -162,6 +162,12 @@ public class ManagementApiClient : IManagementApiClient /// Contains all the methods to call the /users endpoints. /// public IUsersClient Users { get; } + + /// + public IRefreshTokenClient RefreshTokens { get; } + + /// + public ISessionsClient Sessions { get; } private Dictionary DefaultHeaders { get; set; } @@ -213,6 +219,8 @@ public ManagementApiClient(string token, Uri baseUri, IManagementConnection mana Tickets = new TicketsClient(managementConnection, baseUri, DefaultHeaders); UserBlocks = new UserBlocksClient(managementConnection, baseUri, DefaultHeaders); Users = new UsersClient(managementConnection, baseUri, DefaultHeaders); + RefreshTokens = new RefreshTokenClient(managementConnection, baseUri, DefaultHeaders); + Sessions = new SessionsClient(managementConnection, baseUri, DefaultHeaders); } /// diff --git a/src/Auth0.ManagementApi/Models/RefreshTokens/Device.cs b/src/Auth0.ManagementApi/Models/RefreshTokens/Device.cs new file mode 100644 index 00000000..2029ecac --- /dev/null +++ b/src/Auth0.ManagementApi/Models/RefreshTokens/Device.cs @@ -0,0 +1,46 @@ +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.RefreshTokens +{ + /// + /// Device used while issuing/exchanging the refresh token/Session + /// + public class Device + { + /// + /// First IP address associated with the refresh token/Session + /// + [JsonProperty("initial_ip")] + public string InitialIp { get; set; } + + /// + /// First autonomous system number associated with the refresh token/Session + /// + [JsonProperty("initial_asn")] + public string InitialAsn { get; set; } + + /// + /// First user agent associated with the refresh token/Session + /// + [JsonProperty("initial_user_agent")] + public string InitialUserAgent { get; set; } + + /// + /// Last IP address associated with the refresh token/Session + /// + [JsonProperty("last_ip")] + public string LastIp { get; set; } + + /// + /// Last autonomous system number associated with the refresh token/Session + /// + [JsonProperty("last_asn")] + public string LastAsn { get; set; } + + /// + /// Last user agent associated with the refresh token/Session + /// + [JsonProperty("last_user_agent")] + public string LastUserAgent { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/RefreshTokens/RefreshTokenGetRequest.cs b/src/Auth0.ManagementApi/Models/RefreshTokens/RefreshTokenGetRequest.cs new file mode 100644 index 00000000..0f500684 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/RefreshTokens/RefreshTokenGetRequest.cs @@ -0,0 +1,13 @@ +namespace Auth0.ManagementApi.Models.RefreshTokens +{ + /// + /// Represents the information required to Get + /// + public class RefreshTokenGetRequest + { + /// + /// ID of the refresh token to retrieve + /// + public string Id { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/RefreshTokens/RefreshTokenInformation.cs b/src/Auth0.ManagementApi/Models/RefreshTokens/RefreshTokenInformation.cs new file mode 100644 index 00000000..5da40bd5 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/RefreshTokens/RefreshTokenInformation.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.RefreshTokens +{ + public class RefreshTokenInformation : SessionsBase + { + /// + /// ID of the client application granted with this refresh token + /// + [JsonProperty("client_id")] + public string ClientId { get; set; } + + /// + /// ID of the authenticated session used to obtain this refresh-token + /// + [JsonProperty("session_id")] + public string SessionId { get; set; } + + /// + /// True if the token is a rotating refresh token + /// + [JsonProperty("rotating")] + public bool? Rotating { get; set; } + + /// + /// + /// + [JsonProperty("resource_servers")] + public IList ResourceServers { get; set; } + + /// + /// The date and time when the refresh token was last exchanged + /// + [JsonProperty("last_exchanged_at")] + public DateTime? LastExchangedAt { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/RefreshTokens/ResourceServer.cs b/src/Auth0.ManagementApi/Models/RefreshTokens/ResourceServer.cs new file mode 100644 index 00000000..7b22d4fd --- /dev/null +++ b/src/Auth0.ManagementApi/Models/RefreshTokens/ResourceServer.cs @@ -0,0 +1,18 @@ +namespace Auth0.ManagementApi.Models.RefreshTokens +{ + /// + /// A list of the resource server IDs associated to this refresh-token and their granted scopes + /// + public class ResourceServer + { + /// + /// Resource server ID + /// + public string Audience { get; set; } + + /// + /// List of scopes for the refresh token + /// + public string Scopes { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Sessions/Authentication.cs b/src/Auth0.ManagementApi/Models/Sessions/Authentication.cs new file mode 100644 index 00000000..e12cdef2 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Sessions/Authentication.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.Sessions +{ + public class Authentication + { + /// + /// Contains the authentication methods a user has completed during their session + /// + [JsonProperty("methods")] + public IList Methods { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Sessions/AuthenticationMethods.cs b/src/Auth0.ManagementApi/Models/Sessions/AuthenticationMethods.cs new file mode 100644 index 00000000..742e5bd8 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Sessions/AuthenticationMethods.cs @@ -0,0 +1,29 @@ +using System; +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.Sessions +{ + /// + /// Authentication signal details + /// + public class AuthenticationMethods + { + /// + /// One of: "federated", "passkey", "pwd", "sms", "email", "mfa", "mock" or a custom method denoted by a URL + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Timestamp of when the signal was received + /// + [JsonProperty("timestamp")] + public DateTime? Timestamp { get; set; } + + /// + /// A specific MFA factor. Only present when "name" is set to "mfa" + /// + [JsonProperty("^type$")] + public string Type { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Sessions/ClientDetails.cs b/src/Auth0.ManagementApi/Models/Sessions/ClientDetails.cs new file mode 100644 index 00000000..6fcf9a84 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Sessions/ClientDetails.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.Sessions +{ + /// + /// Client details for the session + /// + public class ClientDetails + { + /// + /// ID of client for the session + /// + [JsonProperty("client_id")] + public string ClientId { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Sessions/Sessions.cs b/src/Auth0.ManagementApi/Models/Sessions/Sessions.cs new file mode 100644 index 00000000..d7d1704e --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Sessions/Sessions.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models.Sessions +{ + public class Sessions : SessionsBase + { + /// + /// The date and time when the session was last updated + /// + [JsonProperty("updated_at")] + public DateTime? UpdatedAt { get; set; } + + /// + /// The date and time when the session was last authenticated + /// + [JsonProperty("authenticated_at")] + public DateTime? AuthenticatedAt { get; set; } + + /// + /// The date and time last successful user interaction with the session + /// + [JsonProperty("last_interacted_at")] + public DateTime? LastInteractedAt { get; set; } + + /// + [JsonProperty("clients")] + public IList Clients { get; set; } + + /// + /// Details about authentication signals obtained during the login flow + /// + [JsonProperty("authentication")] + public Authentication Authentication { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/Sessions/SessionsGetRequest.cs b/src/Auth0.ManagementApi/Models/Sessions/SessionsGetRequest.cs new file mode 100644 index 00000000..89005335 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/Sessions/SessionsGetRequest.cs @@ -0,0 +1,13 @@ +namespace Auth0.ManagementApi.Models.Sessions +{ + /// + /// Represents the information required to Get + /// + public class SessionsGetRequest + { + /// + /// ID of session to retrieve + /// + public string Id { get; set; } + } +} \ No newline at end of file diff --git a/src/Auth0.ManagementApi/Models/SessionsBase.cs b/src/Auth0.ManagementApi/Models/SessionsBase.cs new file mode 100644 index 00000000..bed1a1a2 --- /dev/null +++ b/src/Auth0.ManagementApi/Models/SessionsBase.cs @@ -0,0 +1,43 @@ +using System; +using Auth0.ManagementApi.Models.RefreshTokens; +using Newtonsoft.Json; + +namespace Auth0.ManagementApi.Models +{ + public class SessionsBase + { + /// + /// The ID of the refresh token + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// ID of the user which can be used when interacting with other APIs. + /// + [JsonProperty("user_id")] + public string UserId { get; set; } + + /// + /// The date and time when the refresh token was created + /// + [JsonProperty("created_at")] + public DateTime? CreatedAt { get; set; } + + /// + /// The date and time when the refresh token will expire if idle + /// + [JsonProperty("idle_expires_at")] + public DateTime? IdleExpiresAt { get; set; } + + /// + /// The date and time when the refresh token will expire + /// + [JsonProperty("expires_at")] + public DateTime? ExpiresAt { get; set; } + + /// + [JsonProperty("device")] + public Device Device { get; set; } + } +} \ No newline at end of file diff --git a/tests/Auth0.ManagementApi.IntegrationTests/Auth0.ManagementApi.IntegrationTests.csproj b/tests/Auth0.ManagementApi.IntegrationTests/Auth0.ManagementApi.IntegrationTests.csproj index fc419af6..4fec364d 100644 --- a/tests/Auth0.ManagementApi.IntegrationTests/Auth0.ManagementApi.IntegrationTests.csproj +++ b/tests/Auth0.ManagementApi.IntegrationTests/Auth0.ManagementApi.IntegrationTests.csproj @@ -8,6 +8,18 @@ + + Always + + + Always + + + Always + + + Always + diff --git a/tests/Auth0.ManagementApi.IntegrationTests/Data/GetRefreshTokenResponse.json b/tests/Auth0.ManagementApi.IntegrationTests/Data/GetRefreshTokenResponse.json new file mode 100644 index 00000000..d0df6b91 --- /dev/null +++ b/tests/Auth0.ManagementApi.IntegrationTests/Data/GetRefreshTokenResponse.json @@ -0,0 +1,17 @@ +{ + "id": "6fsdgrfsU4dh510", + "user_id": "auth0|8374f7459j7493u766335", + "client_id": "Hwo482a51heU632d34", + "created_at": "2024-05-10T12:04:22.3452", + "updated_at": "2024-05-10T12:04:22.3452", + "idle_expires_at": "2024-05-21T12:29:12.4251", + "expires_at": "2024-06-21T18:29:12.4251", + "session_id": "2Lw8dT76wJpOl924", + "rotating": "true", + "resource_servers": [ + { + "audience": "http://myapi.com", + "scopes": "read:users" + } + ] +} \ No newline at end of file diff --git a/tests/Auth0.ManagementApi.IntegrationTests/Data/GetSessionsResponse.json b/tests/Auth0.ManagementApi.IntegrationTests/Data/GetSessionsResponse.json new file mode 100644 index 00000000..7611eaaa --- /dev/null +++ b/tests/Auth0.ManagementApi.IntegrationTests/Data/GetSessionsResponse.json @@ -0,0 +1,29 @@ +{ + "id": "2Lw8dT76wJpOl924", + "user_id": "auth0|8374f7459j7493u84335", + "created_at": "2024-05-10T12:04:22.3452", + "updated_at": "2024-05-10T12:04:22.3452", + "authenticated_at": "2024-05-21T11:29:12.4251", + "authentication": { + "methods": [ + { + "name": "pwd", + "timestamp": "2024-05-21T11:29:12.4251" + } + ] + }, + "idle_expires_at": "2024-05-21T12:29:12.4251", + "expires_at": "2024-05-21T18:29:12.4251", + "device": { + "initial_ip": "142.250.184.206", + "last_ip": "142.250.184.206", + "initial_user_agent": "Mozilla/5.0...", + "initial_asn": "8612", + "last_asn": "8612" + }, + "clients": [ + { + "client_id": "Hwo482a51heU632d34" + } + ] +} \ No newline at end of file diff --git a/tests/Auth0.ManagementApi.IntegrationTests/Data/UserGetRefreshTokensResponse.json b/tests/Auth0.ManagementApi.IntegrationTests/Data/UserGetRefreshTokensResponse.json new file mode 100644 index 00000000..1ae9e255 --- /dev/null +++ b/tests/Auth0.ManagementApi.IntegrationTests/Data/UserGetRefreshTokensResponse.json @@ -0,0 +1,38 @@ +{ + "tokens": [ + { + "id": "6srfsU4dh510", + "user_id": "auth0|8374f7459j7493u84335", + "client_id": "Hwo482a51heU632d34", + "created_at": "2024-05-10T12:04:22.3452", + "updated_at": "2024-05-10T12:04:22.3452", + "idle_expires_at": "2024-05-21T12:29:12.4251", + "expires_at": "2024-06-21T18:29:12.4251", + "session_id": "2Lw8dT76wJpOl924", + "rotating": "true", + "resource_servers": [ + { + "audience": "http://myapi.com", + "scopes": "read:users" + } + ] + }, + { + "id": "6fsdgrfsU4dh510", + "user_id": "auth0|8374f7459j7493u766335", + "client_id": "Hwo482a51heU632d34", + "created_at": "2024-05-10T12:04:22.3452", + "updated_at": "2024-05-10T12:04:22.3452", + "idle_expires_at": "2024-05-21T12:29:12.4251", + "expires_at": "2024-06-21T18:29:12.4251", + "session_id": "2Lw8dT76wJpOl924", + "rotating": "true", + "resource_servers": [ + { + "audience": "http://myapi.com", + "scopes": "read:users" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/Auth0.ManagementApi.IntegrationTests/Data/UserGetSessionsResponse.json b/tests/Auth0.ManagementApi.IntegrationTests/Data/UserGetSessionsResponse.json new file mode 100644 index 00000000..fa7b3186 --- /dev/null +++ b/tests/Auth0.ManagementApi.IntegrationTests/Data/UserGetSessionsResponse.json @@ -0,0 +1,63 @@ +{ + "sessions": [ + { + "id": "2Lw8dT76wJpOl924", + "user_id": "auth0|8374f7459j7493u84335", + "created_at": "2024-05-10T12:04:22.3452", + "updated_at": "2024-05-10T12:04:22.3452", + "authenticated_at": "2024-05-21T11:29:12.4251", + "authentication": { + "methods": [ + { + "name": "pwd", + "timestamp": "2024-05-21T11:29:12.4251" + } + ] + }, + "idle_expires_at": "2024-05-21T12:29:12.4251", + "expires_at": "2024-05-21T18:29:12.4251", + "device": { + "initial_ip": "142.250.184.206", + "last_ip": "142.250.184.206", + "initial_user_agent": "Mozilla/5.0...", + "initial_asn": "8612", + "last_asn": "8612" + }, + "clients": [ + { + "client_id": "Hwo482a51heU632d34" + } + ] + }, + { + "id": "1Lw8dT76wJpOl1024", + "user_id": "auth0|1234f7459j7493u84335", + "created_at": "2024-05-10T12:04:22.3452", + "updated_at": "2024-05-10T12:04:22.3452", + "authenticated_at": "2024-05-21T11:29:12.4251", + "authentication": { + "methods": [ + { + "name": "pwd", + "timestamp": "2024-05-21T11:29:12.4251" + } + ] + }, + "idle_expires_at": "2024-05-21T12:29:12.4251", + "expires_at": "2024-05-21T18:29:12.4251", + "device": { + "initial_ip": "142.250.184.206", + "last_ip": "142.250.184.206", + "initial_user_agent": "Mozilla/5.0...", + "initial_asn": "8612", + "last_asn": "8612" + }, + "clients": [ + { + "client_id": "Hwo482a51heU632d34" + } + ] + } + ], + "next": "U632d3Hwo482a51heU632d34Hwo482" +} \ No newline at end of file diff --git a/tests/Auth0.ManagementApi.IntegrationTests/RefreshTokensTest.cs b/tests/Auth0.ManagementApi.IntegrationTests/RefreshTokensTest.cs new file mode 100644 index 00000000..0a65b09c --- /dev/null +++ b/tests/Auth0.ManagementApi.IntegrationTests/RefreshTokensTest.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +using Auth0.IntegrationTests.Shared.CleanUp; +using Auth0.ManagementApi.IntegrationTests.Testing; +using Auth0.ManagementApi.Models.RefreshTokens; + +using FluentAssertions; +using Xunit; + +namespace Auth0.ManagementApi.IntegrationTests; + +public class RefreshTokensTestFixture : TestBaseFixture +{ + public override async Task DisposeAsync() + { + foreach (KeyValuePair> entry in identifiers) + { + await ManagementTestBaseUtils.CleanupAsync(ApiClient, entry.Key, entry.Value); + } + + ApiClient.Dispose(); + } +} + +public class RefreshTokensTest: IClassFixture +{ + RefreshTokensTestFixture fixture; + + public RefreshTokensTest(RefreshTokensTestFixture fixture) + { + this.fixture = fixture; + } + + [Fact] + public async Task Test_get_refresh_token_throws_argument_null_exception_when_null_input() + { + await Assert.ThrowsAsync(() => fixture.ApiClient.RefreshTokens.GetAsync(null)); + } + + [Fact] + public async Task Test_get_refresh_token_throws_argument_exception_when_null_input() + { + await Assert.ThrowsAsync(() => fixture.ApiClient.RefreshTokens.GetAsync(new RefreshTokenGetRequest())); + } + + [Fact] + public async Task Test_get_refresh_token_returns_refresh_token() + { + var sampleRefreshTokenResponse = await File.ReadAllTextAsync("./Data/GetRefreshTokenResponse.json"); + var httpManagementClientConnection = new HttpClientManagementConnection(); + var refreshToken = httpManagementClientConnection.DeserializeContent(sampleRefreshTokenResponse, null); + + refreshToken.Should().NotBeNull(); + refreshToken.Id.Should().Be("6fsdgrfsU4dh510"); + refreshToken.UserId.Should().Be("auth0|8374f7459j7493u766335"); + refreshToken.CreatedAt.Should().Be(DateTime.Parse("2024-05-10T12:04:22.3452")); + refreshToken.IdleExpiresAt.Should().Be(DateTime.Parse("2024-05-21T12:29:12.4251")); + refreshToken.ExpiresAt.Should().Be(DateTime.Parse("2024-06-21T18:29:12.4251")); + refreshToken.SessionId.Should().Be("2Lw8dT76wJpOl924"); + refreshToken.Rotating.Should().Be(true); + refreshToken.ResourceServers.Count.Should().Be(1); + refreshToken.ResourceServers.First().Audience.Should().Be("http://myapi.com"); + refreshToken.ResourceServers.First().Scopes.Should().Be("read:users"); + } +} \ No newline at end of file diff --git a/tests/Auth0.ManagementApi.IntegrationTests/SessionsTests.cs b/tests/Auth0.ManagementApi.IntegrationTests/SessionsTests.cs new file mode 100644 index 00000000..bda901e8 --- /dev/null +++ b/tests/Auth0.ManagementApi.IntegrationTests/SessionsTests.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +using Auth0.IntegrationTests.Shared.CleanUp; +using Auth0.ManagementApi.IntegrationTests.Testing; +using Auth0.ManagementApi.Models.Sessions; + +using FluentAssertions; +using Xunit; + +namespace Auth0.ManagementApi.IntegrationTests; +public class SessionsTestFixture : TestBaseFixture +{ + public override async Task DisposeAsync() + { + foreach (KeyValuePair> entry in identifiers) + { + await ManagementTestBaseUtils.CleanupAsync(ApiClient, entry.Key, entry.Value); + } + + ApiClient.Dispose(); + } +} + +public class SessionsTest: IClassFixture +{ + SessionsTestFixture fixture; + + public SessionsTest(SessionsTestFixture fixture) + { + this.fixture = fixture; + } + + [Fact] + public async Task Test_get_sessions_throws_argument_null_exception_when_null_input() + { + await Assert.ThrowsAsync(() => fixture.ApiClient.Sessions.GetAsync(null)); + } + + [Fact] + public async Task Test_get_sessions_throws_argument_exception_when_null_input() + { + await Assert.ThrowsAsync(() => fixture.ApiClient.Sessions.GetAsync(new SessionsGetRequest())); + } + + [Fact] + public async Task Test_get_sessions_returns_sessions() + { + var sampleSessionsResponse = await File.ReadAllTextAsync("./Data/GetSessionsResponse.json"); + var httpManagementClientConnection = new HttpClientManagementConnection(); + var sessions = httpManagementClientConnection.DeserializeContent(sampleSessionsResponse, null); + sessions.Id.Should().Be("2Lw8dT76wJpOl924"); + sessions.UserId.Should().Be("auth0|8374f7459j7493u84335"); + sessions.CreatedAt.Should().Be(DateTime.Parse("2024-05-10T12:04:22.3452")); + sessions.Authentication.Methods.Count.Should().Be(1); + sessions.Authentication.Methods.First().Name.Should().Be("pwd"); + sessions.Authentication.Methods.First().Timestamp.Should().Be(DateTime.Parse("2024-05-21T11:29:12.4251")); + sessions.Device.InitialIp.Should().Be("142.250.184.206"); + sessions.Device.LastIp.Should().Be("142.250.184.206"); + sessions.Device.InitialUserAgent.Should().Be("Mozilla/5.0..."); + sessions.Device.InitialAsn.Should().Be("8612"); + sessions.Device.LastAsn.Should().Be("8612"); + } +} \ No newline at end of file