diff --git a/Descope.Test/Descope.Test.csproj b/Descope.Test/Descope.Test.csproj
new file mode 100644
index 0000000..122d27b
--- /dev/null
+++ b/Descope.Test/Descope.Test.csproj
@@ -0,0 +1,47 @@
+
+
+
+ Exe
+ net6.0
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Descope.Test/Descope.Test.sln b/Descope.Test/Descope.Test.sln
new file mode 100644
index 0000000..7d56652
--- /dev/null
+++ b/Descope.Test/Descope.Test.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.002.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Descope.Test", "Descope.Test.csproj", "{E2E0EF99-CE4C-40BA-8A8E-532F14D47F7A}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E2E0EF99-CE4C-40BA-8A8E-532F14D47F7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E2E0EF99-CE4C-40BA-8A8E-532F14D47F7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E2E0EF99-CE4C-40BA-8A8E-532F14D47F7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E2E0EF99-CE4C-40BA-8A8E-532F14D47F7A}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {18F8C6D8-027A-45D4-BFFC-ABFF27D9416F}
+ EndGlobalSection
+EndGlobal
diff --git a/Descope.Test/IntegrationTests/Authentication/AuthenticationTests.cs b/Descope.Test/IntegrationTests/Authentication/AuthenticationTests.cs
new file mode 100644
index 0000000..922b065
--- /dev/null
+++ b/Descope.Test/IntegrationTests/Authentication/AuthenticationTests.cs
@@ -0,0 +1,146 @@
+using Xunit;
+
+namespace Descope.Test.Integration
+{
+ public class AuthenticationTests
+ {
+ private readonly DescopeClient _descopeClient = IntegrationTestSetup.InitDescopeClient();
+
+ [Fact]
+ public async Task Authentication_ValidateAndRefresh()
+ {
+ string? loginId = null;
+ try
+ {
+ await _descopeClient.Management.User.DeleteAllTestUsers();
+ // Create a logged in test user
+ var testUser = await IntegrationTestSetup.InitTestUser(_descopeClient);
+ loginId = testUser.User.LoginIds.First();
+
+ // Make sure the session is valid
+ var token = await _descopeClient.Auth.ValidateSession(testUser.AuthInfo.SessionJwt);
+ Assert.Equal(testUser.AuthInfo.SessionJwt, token.Jwt);
+ Assert.NotEmpty(token.Id);
+ Assert.NotEmpty(token.ProjectId);
+
+ // Refresh and see we got a new token
+ var refreshedToken = await _descopeClient.Auth.RefreshSession(testUser.AuthInfo.RefreshJwt!);
+ Assert.NotNull(refreshedToken.RefreshExpiration);
+ Assert.Equal(token.Id, refreshedToken.Id);
+ Assert.Equal(token.ProjectId, refreshedToken.ProjectId);
+ }
+ finally
+ {
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task Authentication_ExchangeAccessKeyAndMe()
+ {
+ string? loginId = null;
+ string? accessKeyId = null;
+ try
+ {
+ // Create a logged in test user
+ var testUser = await IntegrationTestSetup.InitTestUser(_descopeClient);
+ loginId = testUser.User.LoginIds.First();
+
+ // Create an access key and exchange it
+ var accessKeyResponse = await _descopeClient.Management.AccessKey.Create(loginId, userId: testUser.User.UserId);
+ accessKeyId = accessKeyResponse.Key.Id;
+ var token = await _descopeClient.Auth.ExchangeAccessKey(accessKeyResponse.Cleartext);
+ Assert.NotEmpty(token.Id);
+ Assert.NotEmpty(token.ProjectId);
+ Assert.NotEmpty(token.Jwt);
+ }
+ finally
+ {
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ if (!string.IsNullOrEmpty(accessKeyId))
+ {
+ try { await _descopeClient.Management.AccessKey.Delete(accessKeyId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task Authentication_SelectTenant()
+ {
+ string? loginId = null;
+ List tenantIds = new() { };
+ try
+ {
+ // Create a logged in test user
+ var testUser = await IntegrationTestSetup.InitTestUser(_descopeClient);
+ loginId = testUser.User.LoginIds.First();
+
+ // Create a couple of tenants and add to the user
+ var tenantId = await _descopeClient.Management.Tenant.Create(new TenantOptions(Guid.NewGuid().ToString()));
+ tenantIds.Add(tenantId);
+ await _descopeClient.Management.User.AddTenant(loginId, tenantId);
+ tenantId = await _descopeClient.Management.Tenant.Create(new TenantOptions(Guid.NewGuid().ToString()));
+ tenantIds.Add(tenantId);
+ await _descopeClient.Management.User.AddTenant(loginId, tenantId);
+ var session = await _descopeClient.Auth.SelectTenant(tenantId, testUser.AuthInfo.RefreshJwt!);
+ Assert.NotEmpty(session.SessionToken.Id);
+ Assert.NotEmpty(session.SessionToken.ProjectId);
+ Assert.NotEmpty(session.SessionToken.Jwt);
+ }
+ finally
+ {
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ foreach (var tenantId in tenantIds)
+ {
+ try { await _descopeClient.Management.Tenant.Delete(tenantId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task Authentication_MeAndLogout()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a logged in test user
+ var testUser = await IntegrationTestSetup.InitTestUser(_descopeClient);
+ loginId = testUser.User.LoginIds.First();
+
+ // Me
+ var user = await _descopeClient.Auth.Me(testUser.AuthInfo.RefreshJwt!);
+ Assert.Equal(testUser.User.UserId, user.UserId);
+
+ // Logout
+ await _descopeClient.Auth.LogOut(testUser.AuthInfo.RefreshJwt!);
+
+ // Try me again
+ async Task Act() => await _descopeClient.Auth.Me(testUser.AuthInfo.RefreshJwt!);
+ DescopeException result = await Assert.ThrowsAsync(Act);
+ Assert.Contains("Expired due to logout", result.Message);
+ }
+ finally
+ {
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+ }
+}
diff --git a/Descope.Test/IntegrationTests/Management/AccessKeyTests.cs b/Descope.Test/IntegrationTests/Management/AccessKeyTests.cs
new file mode 100644
index 0000000..64e2961
--- /dev/null
+++ b/Descope.Test/IntegrationTests/Management/AccessKeyTests.cs
@@ -0,0 +1,160 @@
+using Xunit;
+
+namespace Descope.Test.Integration
+{
+ public class AccessKeyTests
+ {
+ private readonly DescopeClient _descopeClient = IntegrationTestSetup.InitDescopeClient();
+
+ [Fact]
+ public async Task AccessKey_Create_MissingName()
+ {
+ async Task Act() => await _descopeClient.Management.AccessKey.Create(name: "");
+ DescopeException result = await Assert.ThrowsAsync(Act);
+ Assert.Contains("Access key name is required", result.Message);
+ }
+
+ [Fact]
+ public async Task AccessKey_CreateAndUpdate()
+ {
+ string? id = null;
+ try
+ {
+ // Create an access key
+ var accessKey = await _descopeClient.Management.AccessKey.Create(name: Guid.NewGuid().ToString());
+ id = accessKey.Key.Id;
+
+ // Update and compare
+ var updatedName = accessKey.Key.Name + "updated";
+ var updatedKey = await _descopeClient.Management.AccessKey.Update(id: id, name: updatedName);
+ Assert.Equal(updatedKey.Name, updatedKey.Name);
+ }
+ finally
+ {
+ if (!string.IsNullOrEmpty(id))
+ {
+ try { await _descopeClient.Management.AccessKey.Delete(id); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task AccessKey_Update_MissingId()
+ {
+ async Task Act() => await _descopeClient.Management.AccessKey.Update("", "name");
+ DescopeException result = await Assert.ThrowsAsync(Act);
+ Assert.Contains("ID is required", result.Message);
+ }
+
+ [Fact]
+ public async Task AccessKey_Update_MissingName()
+ {
+ async Task Act() => await _descopeClient.Management.AccessKey.Update("someId", "");
+ DescopeException result = await Assert.ThrowsAsync(Act);
+ Assert.Contains("name cannot be updated to empty", result.Message);
+ }
+
+ [Fact]
+ public async Task Accesskey_ActivateDeactivate()
+ {
+ string? id = null;
+ try
+ {
+ // Create an access key
+ var accessKey = await _descopeClient.Management.AccessKey.Create(name: Guid.NewGuid().ToString());
+ id = accessKey.Key.Id;
+
+ // Deactivate
+ await _descopeClient.Management.AccessKey.Deactivate(id);
+ var loadedKey = await _descopeClient.Management.AccessKey.Load(id);
+ Assert.Equal("inactive", loadedKey.Status);
+
+ // Activate
+ await _descopeClient.Management.AccessKey.Activate(id);
+ loadedKey = await _descopeClient.Management.AccessKey.Load(id);
+ Assert.Equal("active", loadedKey.Status);
+ }
+ finally
+ {
+ if (!string.IsNullOrEmpty(id))
+ {
+ try { await _descopeClient.Management.AccessKey.Delete(id); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task AccessKey_Activate_MissingId()
+ {
+ async Task Act() => await _descopeClient.Management.AccessKey.Activate("");
+ DescopeException result = await Assert.ThrowsAsync(Act);
+ Assert.Contains("ID is required", result.Message);
+ }
+
+ [Fact]
+ public async Task AccessKey_Deactivate_MissingId()
+ {
+ async Task Act() => await _descopeClient.Management.AccessKey.Deactivate("");
+ DescopeException result = await Assert.ThrowsAsync(Act);
+ Assert.Contains("ID is required", result.Message);
+ }
+
+ [Fact]
+ public async Task AccessKey_Load_MissingId()
+ {
+ async Task Act() => await _descopeClient.Management.AccessKey.Load("");
+ DescopeException result = await Assert.ThrowsAsync(Act);
+ Assert.Contains("Access key ID is required", result.Message);
+ }
+
+ [Fact]
+ public async Task AccessKey_SearchAll()
+ {
+ string? id = null;
+ try
+ {
+ // Create an access key
+ var accessKey = await _descopeClient.Management.AccessKey.Create(name: Guid.NewGuid().ToString());
+ id = accessKey.Key.Id;
+
+ // Search for it
+ var accessKeys = await _descopeClient.Management.AccessKey.SearchAll();
+ var key = accessKeys.Find(key => key.Id == id);
+ Assert.NotNull(key);
+ }
+ finally
+ {
+ if (!string.IsNullOrEmpty(id))
+ {
+ try { await _descopeClient.Management.AccessKey.Delete(id); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task AccessKey_Delete()
+ {
+ // Arrange
+ var accessKey = await _descopeClient.Management.AccessKey.Create(name: Guid.NewGuid().ToString());
+
+ // Act
+ await _descopeClient.Management.AccessKey.Delete(accessKey.Key.Id);
+
+ // Assert
+ var accessKeys = await _descopeClient.Management.AccessKey.SearchAll(new List() { accessKey.Key.Id });
+ Assert.Empty(accessKeys);
+ }
+
+ [Fact]
+ public async Task Accesskey_Delete_MissingId()
+ {
+ async Task Act() => await _descopeClient.Management.AccessKey.Delete("");
+ DescopeException result = await Assert.ThrowsAsync(Act);
+ Assert.Contains("Access key ID is required", result.Message);
+ }
+
+ }
+}
diff --git a/Descope.Test/IntegrationTests/Management/ProjectTests.cs b/Descope.Test/IntegrationTests/Management/ProjectTests.cs
new file mode 100644
index 0000000..2bff7e7
--- /dev/null
+++ b/Descope.Test/IntegrationTests/Management/ProjectTests.cs
@@ -0,0 +1,36 @@
+using Xunit;
+
+namespace Descope.Test.Integration
+{
+ public class ProjectTests
+ {
+ private readonly DescopeClient _descopeClient = IntegrationTestSetup.InitDescopeClient();
+
+ [Fact]
+ public async Task Project_ExportImport()
+ {
+ var imported_project = await _descopeClient.Management.Project.Export();
+ await _descopeClient.Management.Project.Import(imported_project);
+ }
+
+ [Fact(Skip = "Test fails due to theme import")]
+ public async Task Project_CloneRenameDelete()
+ {
+ // Clone the current project
+ var name = Guid.NewGuid().ToString().Split("-").First();
+ var result = await _descopeClient.Management.Project.Clone(name, "");
+ Assert.NotNull(result);
+
+ // Delete cloned project
+ await _descopeClient.Management.Project.Delete(result.ProjectId);
+
+ // Rename
+ var new_name = Guid.NewGuid().ToString().Split("-").First();
+ await _descopeClient.Management.Project.Rename(new_name);
+
+ // Rename again so we will have original name
+ await _descopeClient.Management.Project.Rename("dotnet");
+ }
+
+ }
+}
diff --git a/Descope.Test/IntegrationTests/Management/TenantTests.cs b/Descope.Test/IntegrationTests/Management/TenantTests.cs
new file mode 100644
index 0000000..1b69c22
--- /dev/null
+++ b/Descope.Test/IntegrationTests/Management/TenantTests.cs
@@ -0,0 +1,133 @@
+using Xunit;
+
+namespace Descope.Test.Integration
+{
+ public class TenantTests
+ {
+ private readonly DescopeClient _descopeClient = IntegrationTestSetup.InitDescopeClient();
+
+ [Fact]
+ public async Task Tenant_CreateAndLoad()
+ {
+ string? tenantId = null;
+ try
+ {
+ // Create a tenant
+ var name = Guid.NewGuid().ToString();
+ var domain = name + ".com";
+ var options = new TenantOptions(name)
+ {
+ SelfProvisioningDomains = new List { domain },
+ };
+ tenantId = await _descopeClient.Management.Tenant.Create(options: options);
+
+ // Load and compare
+ var loadedTenant = await _descopeClient.Management.Tenant.LoadById(tenantId);
+ Assert.Equal(loadedTenant.Name, options.Name);
+ Assert.NotNull(loadedTenant.SelfProvisioningDomains);
+ Assert.Contains(domain, loadedTenant.SelfProvisioningDomains);
+ }
+ finally
+ {
+ if (!string.IsNullOrEmpty(tenantId))
+ {
+ try { await _descopeClient.Management.Tenant.Delete(tenantId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task Tenant_Create_MissingName()
+ {
+ async Task Act() => await _descopeClient.Management.Tenant.Create(new TenantOptions(""));
+ DescopeException result = await Assert.ThrowsAsync(Act);
+ Assert.Contains("Tenant name is required", result.Message);
+ }
+
+ [Fact]
+ public async Task Tenant_UpdateAndSearch()
+ {
+ string? tenantId = null;
+ try
+ {
+ // Create a tenant
+ string tenantName = Guid.NewGuid().ToString();
+ tenantId = await _descopeClient.Management.Tenant.Create(options: new TenantOptions(tenantName));
+ var updatedTenantName = tenantName + "updated";
+
+ // Update and compare
+ await _descopeClient.Management.Tenant.Update(tenantId, new TenantOptions(updatedTenantName));
+ var tenants = await _descopeClient.Management.Tenant.SearchAll(new TenantSearchOptions { Ids = new List { tenantId } });
+ Assert.Single(tenants);
+ Assert.Equal(tenants[0].Name, updatedTenantName);
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(tenantId))
+ {
+ try { await _descopeClient.Management.Tenant.Delete(tenantId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task Tenant_Update_MissingId()
+ {
+ async Task Act() => await _descopeClient.Management.Tenant.Update("", new TenantOptions(""));
+ DescopeException result = await Assert.ThrowsAsync(Act);
+ Assert.Contains("Tenant ID is required", result.Message);
+ }
+
+ [Fact]
+ public async Task Tenant_Update_MissingName()
+ {
+ async Task Act() => await _descopeClient.Management.Tenant.Update("someId", new TenantOptions(""));
+ DescopeException result = await Assert.ThrowsAsync(Act);
+ Assert.Contains("name cannot be updated to empty", result.Message);
+ }
+
+ [Fact]
+ public async Task Tenant_DeleteAndLoadAll()
+ {
+ string? tenantId = null;
+ try
+ {
+ // Create a tenant
+ var id = await _descopeClient.Management.Tenant.Create(options: new TenantOptions(Guid.NewGuid().ToString()));
+ tenantId = id;
+
+ // Delete it
+ await _descopeClient.Management.Tenant.Delete(id);
+ tenantId = null;
+
+ // Load all and make sure it's gone
+ var tenants = await _descopeClient.Management.Tenant.LoadAll();
+ foreach (var tenant in tenants)
+ {
+ Assert.NotEqual(id, tenant.Id);
+ }
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(tenantId))
+ {
+ try { await _descopeClient.Management.Tenant.Delete(tenantId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task Tenant_Delete_MissingId()
+ {
+ async Task Act() => await _descopeClient.Management.Tenant.Delete("");
+ DescopeException result = await Assert.ThrowsAsync(Act);
+ Assert.Contains("Tenant ID is required", result.Message);
+ }
+ }
+
+}
diff --git a/Descope.Test/IntegrationTests/Management/UserTests.cs b/Descope.Test/IntegrationTests/Management/UserTests.cs
new file mode 100644
index 0000000..1e07964
--- /dev/null
+++ b/Descope.Test/IntegrationTests/Management/UserTests.cs
@@ -0,0 +1,637 @@
+using Xunit;
+
+namespace Descope.Test.Integration
+{
+ public class UserTests
+ {
+ private readonly DescopeClient _descopeClient = IntegrationTestSetup.InitDescopeClient();
+
+ [Fact]
+ public async Task User_Create()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a user
+ var name = Guid.NewGuid().ToString();
+ var result = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Email = name + "@test.com",
+ });
+ loginId = result.LoginIds.First();
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task User_CreateBatch()
+ {
+ List? loginIds = null;
+ try
+ {
+ // Prepare batch info
+ var user1 = Guid.NewGuid().ToString();
+ var user2 = Guid.NewGuid().ToString();
+ var batchUsers = new List()
+ {
+ new(loginId: user1)
+ {
+ Email = user1 + "@test.com",
+ VerifiedEmail = true,
+ },
+ new(loginId: user2)
+ {
+ Email = user2 + "@test.com",
+ VerifiedEmail = false,
+ }
+ };
+
+ // Create batch and check
+ var result = await _descopeClient.Management.User.CreateBatch(batchUsers);
+ Assert.True(result.CreatedUsers.Count == 2);
+ loginIds = new List();
+ foreach (var createdUser in result.CreatedUsers)
+ {
+ var loginId = createdUser.LoginIds.First();
+ loginIds.Add(loginId);
+ if (loginId == user1)
+ {
+ Assert.True(createdUser.VerifiedEmail);
+ }
+ else if (loginId == user2)
+ {
+ Assert.False(createdUser.VerifiedEmail);
+ }
+ }
+ }
+ finally
+ {
+ // Cleanup
+ if (loginIds != null)
+ {
+ foreach (var loginId in loginIds)
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task User_Update()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a user
+ var name = Guid.NewGuid().ToString();
+ var createResult = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Email = name + "@test.com",
+ VerifiedEmail = true,
+ GivenName = "a",
+ });
+ Assert.Equal("a", createResult.GivenName);
+ loginId = createResult.LoginIds.First();
+
+ // Update it
+ var updateResult = await _descopeClient.Management.User.Update(loginId, new UserRequest()
+ {
+ Email = name + "@test.com",
+ VerifiedEmail = true,
+ GivenName = "b",
+ });
+ Assert.Equal("b", updateResult.GivenName);
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task User_Activate()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a user
+ var name = Guid.NewGuid().ToString();
+ var createResult = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Email = name + "@test.com",
+ VerifiedEmail = true,
+ });
+ Assert.Equal("invited", createResult.Status);
+ loginId = createResult.LoginIds.First();
+
+ // Act
+ var updateResult = await _descopeClient.Management.User.Deactivate(loginId);
+ Assert.Equal("disabled", updateResult.Status);
+ updateResult = await _descopeClient.Management.User.Activate(loginId);
+ Assert.Equal("enabled", updateResult.Status);
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task User_UpdateLoginId()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a user
+ var name = Guid.NewGuid().ToString();
+ var createResult = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Email = name + "@test.com",
+ VerifiedEmail = true,
+ });
+ loginId = createResult.LoginIds.First();
+
+ // Act
+ var updatedLoginId = Guid.NewGuid().ToString();
+ var updateResult = await _descopeClient.Management.User.UpdateLoginId(loginId, updatedLoginId);
+ loginId = updatedLoginId;
+
+ // Assert
+ Assert.Equal(updatedLoginId, updateResult.LoginIds.First());
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task User_UpdateEmail()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a user
+ var name = Guid.NewGuid().ToString();
+ var createResult = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Email = name + "@test.com",
+ VerifiedEmail = true,
+ });
+ loginId = createResult.LoginIds.First();
+
+ // Act
+ var updatedEmail = Guid.NewGuid().ToString() + "@test.com";
+ var updateResult = await _descopeClient.Management.User.UpdateEmail(loginId, updatedEmail, true);
+
+ // Assert
+ Assert.Equal(updatedEmail, updateResult.Email);
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task User_UpdatePhone()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a user
+ var name = Guid.NewGuid().ToString();
+ var createResult = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Phone = "+972555555555",
+ VerifiedPhone = true,
+ });
+ loginId = createResult.LoginIds.First();
+
+ // Act
+ var updatedPhone = "+972555555556";
+ var updateResult = await _descopeClient.Management.User.UpdatePhone(loginId, updatedPhone, true);
+
+ // Assert
+ Assert.Equal(updatedPhone, updateResult.Phone);
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+
+ [Fact]
+ public async Task User_UpdateDisplayName()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a user
+ var name = Guid.NewGuid().ToString();
+ var createResult = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Phone = "+972555555555",
+ Name = "a"
+ });
+ loginId = createResult.LoginIds.First();
+
+ // Act
+ var updateResult = await _descopeClient.Management.User.UpdateDisplayName(loginId, "b");
+
+ // Assert
+ Assert.Equal("b", updateResult.Name);
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task User_UpdateUserNames()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a user
+ var name = Guid.NewGuid().ToString();
+ var createResult = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Phone = "+972555555555",
+ GivenName = "a",
+ MiddleName = "a",
+ FamilyName = "a",
+ });
+ loginId = createResult.LoginIds.First();
+
+ // Act
+ var updateResult = await _descopeClient.Management.User.UpdateUserNames(loginId, "b", "b", "b");
+
+ // Assert
+ Assert.Equal("b", updateResult.GivenName);
+ Assert.Equal("b", updateResult.MiddleName);
+ Assert.Equal("b", updateResult.FamilyName);
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task User_UpdatePicture()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a user
+ var name = Guid.NewGuid().ToString();
+ var createResult = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Phone = "+972555555555",
+ Picture = "https://pics.com/a",
+ });
+ loginId = createResult.LoginIds.First();
+
+ // Act
+ var updateResult = await _descopeClient.Management.User.UpdatePicture(loginId, "https://pics.com/b");
+
+ // Assert
+ Assert.Equal("https://pics.com/b", updateResult.Picture);
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact(Skip = "Requires the custom attribute 'a' to exist on the project")]
+ public async Task User_UpdateCustomAttributes()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a user
+ var name = Guid.NewGuid().ToString();
+ var createResult = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Phone = "+972555555555",
+ CustomAttributes = new Dictionary { { "a", "b" } },
+ });
+ loginId = createResult.LoginIds.First();
+
+ // Update custom attribute
+ var updateResult = await _descopeClient.Management.User.UpdateCustomAttributes(loginId, "a", "c");
+ Assert.NotNull(updateResult.CustomAttributes);
+ Assert.Equal("c", updateResult.CustomAttributes["a"].ToString());
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task User_Roles()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a user
+ var name = Guid.NewGuid().ToString();
+ var createResult = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Phone = "+972555555555",
+ VerifiedPhone = true,
+ });
+ loginId = createResult.LoginIds.First();
+
+ // Check add roles
+ var roleNames = new List { "Tenant Admin" };
+ var updateResult = await _descopeClient.Management.User.AddRoles(loginId, roleNames);
+ Assert.NotNull(updateResult.RoleNames);
+ Assert.Single(updateResult.RoleNames);
+ Assert.Contains("Tenant Admin", updateResult.RoleNames);
+
+ // Check remove roles
+ updateResult = await _descopeClient.Management.User.RemoveRoles(loginId, roleNames);
+ Assert.NotNull(updateResult.RoleNames);
+ Assert.Empty(updateResult.RoleNames);
+
+ // Check set roles
+ updateResult = await _descopeClient.Management.User.SetRoles(loginId, roleNames);
+ Assert.NotNull(updateResult.RoleNames);
+ Assert.Single(updateResult.RoleNames);
+ Assert.Contains("Tenant Admin", updateResult.RoleNames);
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task User_SsoApps()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a user
+ var name = Guid.NewGuid().ToString();
+ var createResult = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Phone = "+972555555555",
+ VerifiedPhone = true,
+ });
+ loginId = createResult.LoginIds.First();
+
+ // Check add sso apps
+ var ssoApps = new List { "descope-default-oidc" };
+ var updateResult = await _descopeClient.Management.User.AddSsoApps(loginId, ssoApps);
+ Assert.NotNull(updateResult.SsoAppIds);
+ Assert.Single(updateResult.SsoAppIds);
+ Assert.Contains("descope-default-oidc", updateResult.SsoAppIds);
+
+ // Check remove sso apps
+ updateResult = await _descopeClient.Management.User.RemoveSsoApps(loginId, ssoApps);
+ Assert.NotNull(updateResult.SsoAppIds);
+ Assert.Empty(updateResult.SsoAppIds);
+
+ // Check set sso apps
+ updateResult = await _descopeClient.Management.User.SetSsoApps(loginId, ssoApps);
+ Assert.NotNull(updateResult.SsoAppIds);
+ Assert.Single(updateResult.SsoAppIds);
+ Assert.Contains("descope-default-oidc", updateResult.SsoAppIds);
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task User_Tenants()
+ {
+ string? loginId = null;
+ string? tenantId = null;
+ try
+ {
+ // Create a user
+ var name = Guid.NewGuid().ToString();
+ var createResult = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Phone = "+972555555555",
+ VerifiedPhone = true,
+ });
+ loginId = createResult.LoginIds.First();
+
+ // Create a tenant
+ tenantId = await _descopeClient.Management.Tenant.Create(new TenantOptions(Guid.NewGuid().ToString()));
+
+ // Check add roles
+ var updateResult = await _descopeClient.Management.User.AddTenant(loginId, tenantId);
+ Assert.NotNull(updateResult.UserTenants);
+ Assert.Single(updateResult.UserTenants);
+ var t = updateResult.UserTenants.Find(t => t.TenantId == tenantId);
+ Assert.NotNull(t);
+
+ // Check remove roles
+ updateResult = await _descopeClient.Management.User.RemoveTenant(loginId, tenantId);
+ Assert.NotNull(updateResult.UserTenants);
+ Assert.Empty(updateResult.UserTenants);
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ if (!string.IsNullOrEmpty(tenantId))
+ {
+ try { await _descopeClient.Management.Tenant.Delete(tenantId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task User_Password()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a user
+ var name = Guid.NewGuid().ToString();
+ var createResult = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Phone = "+972555555555",
+ VerifiedPhone = true,
+ });
+ loginId = createResult.LoginIds.First();
+ Assert.False(createResult.Password);
+
+ // Set a temporary password
+ await _descopeClient.Management.User.SetActivePassword(loginId, "abCD123#$");
+ var loadResult = await _descopeClient.Management.User.Load(loginId);
+ Assert.True(loadResult.Password);
+ await _descopeClient.Management.User.ExpirePassword(loginId);
+ await _descopeClient.Management.User.SetTemporaryPassword(loginId, "abCD123#$");
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task User_DeleteAndSearch()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a user
+ var name = Guid.NewGuid().ToString();
+ var createResult = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Phone = "+972111111111",
+ VerifiedPhone = true,
+ });
+ loginId = createResult.LoginIds.First();
+
+ // Search for it
+ var users = await _descopeClient.Management.User.SearchAll(new SearchUserOptions() { Text = name, Limit = 1 });
+ Assert.Single(users);
+ await _descopeClient.Management.User.Delete(loginId);
+ loginId = null;
+ users = await _descopeClient.Management.User.SearchAll(new SearchUserOptions { Text = name, Limit = 1 });
+ Assert.Empty(users);
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+ [Fact]
+ public async Task User_TestUser()
+ {
+ string? loginId = null;
+ try
+ {
+ // Create a test user
+ var name = Guid.NewGuid().ToString();
+ var createResult = await _descopeClient.Management.User.Create(loginId: name, new UserRequest()
+ {
+ Phone = "+972111111111",
+ VerifiedPhone = true,
+
+ }, testUser: true);
+ loginId = createResult.LoginIds.First();
+
+ // Generate all manor of auth
+ var otp = await _descopeClient.Management.User.GenerateOtpForTestUser(DeliveryMethod.Email, loginId);
+ Assert.Equal(loginId, otp.LoginId);
+ Assert.NotEmpty(otp.Code);
+ var ml = await _descopeClient.Management.User.GenerateMagicLinkForTestUser(DeliveryMethod.Email, loginId);
+ Assert.NotEmpty(ml.Link);
+ Assert.Equal(loginId, ml.LoginId);
+ var el = await _descopeClient.Management.User.GenerateEnchantedLinkForTestUser(loginId);
+ Assert.NotEmpty(el.Link);
+ Assert.NotEmpty(el.PendingRef);
+ Assert.Equal(loginId, el.LoginId);
+ // Note: Enable embedded authentication to test
+ // var eml = await _descopeClient.Management.User.GenerateEmbeddedLink(loginId);
+ // Assert.NotEmpty(eml);
+ }
+ finally
+ {
+ // Cleanup
+ if (!string.IsNullOrEmpty(loginId))
+ {
+ try { await _descopeClient.Management.User.Delete(loginId); }
+ catch { }
+ }
+ }
+ }
+
+ }
+}
diff --git a/Descope.Test/IntegrationTests/Setup.cs b/Descope.Test/IntegrationTests/Setup.cs
new file mode 100644
index 0000000..dc5c322
--- /dev/null
+++ b/Descope.Test/IntegrationTests/Setup.cs
@@ -0,0 +1,57 @@
+using Microsoft.Extensions.Configuration;
+
+namespace Descope.Test.Integration
+{
+ internal class IntegrationTestSetup
+ {
+ internal static DescopeClient InitDescopeClient()
+ {
+ Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Test");
+ var configuration = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettingsTest.json", optional: true, reloadOnChange: true)
+ .AddEnvironmentVariables()
+ .Build();
+
+ var projectId = configuration["AppSettings:ProjectId"] ?? throw new ApplicationException("Can't run tests without a project ID");
+ var managementKey = configuration["AppSettings:ManagementKey"] ?? throw new ApplicationException("Can't run tests without a management key");
+ var baseUrl = configuration["AppSettings:BaseURL"];
+ var isUnsafe = bool.Parse(configuration["AppSettings:Unsafe"] ?? "false");
+
+ var config = new DescopeConfig(projectId: projectId)
+ {
+ ManagementKey = managementKey,
+ BaseURL = baseUrl,
+ Unsafe = isUnsafe,
+ };
+
+ return new DescopeClient(config);
+ }
+
+ internal static async Task InitTestUser(DescopeClient descopeClient)
+ {
+ var loginId = Guid.NewGuid().ToString();
+ var user = await descopeClient.Management.User.Create(loginId: loginId, new UserRequest()
+ {
+ Phone = "+972555555555",
+ VerifiedPhone = true,
+ }, testUser: true);
+
+ var generatedOtp = await descopeClient.Management.User.GenerateOtpForTestUser(DeliveryMethod.Sms, loginId);
+ var authInfo = await descopeClient.Auth.Otp.Verify(DeliveryMethod.Sms, loginId, generatedOtp.Code);
+ return new SignedInTestUser(user, authInfo);
+ }
+
+ }
+
+ internal class SignedInTestUser
+ {
+ internal UserResponse User { get; }
+ internal AuthenticationResponse AuthInfo { get; }
+ internal SignedInTestUser(UserResponse user, AuthenticationResponse authInfo)
+ {
+ User = user;
+ AuthInfo = authInfo;
+ }
+ }
+}
diff --git a/Descope.Test/packages.lock.json b/Descope.Test/packages.lock.json
new file mode 100644
index 0000000..b1d44ac
--- /dev/null
+++ b/Descope.Test/packages.lock.json
@@ -0,0 +1,1240 @@
+{
+ "version": 1,
+ "dependencies": {
+ "net6.0": {
+ "Microsoft.Extensions.Configuration": {
+ "type": "Direct",
+ "requested": "[7.0.0, )",
+ "resolved": "7.0.0",
+ "contentHash": "tldQUBWt/xeH2K7/hMPPo5g8zuLc3Ro9I5d4o/XrxvxOCA2EZBtW7bCHHTc49fcBtvB8tLAb/Qsmfrq+2SJ4vA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "7.0.0",
+ "Microsoft.Extensions.Primitives": "7.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": {
+ "type": "Direct",
+ "requested": "[7.0.0, )",
+ "resolved": "7.0.0",
+ "contentHash": "RIkfqCkvrAogirjsqSrG1E1FxgrLsOZU2nhRbl07lrajnxzSU2isj2lwQah0CtCbLWo/pOIukQzM1GfneBUnxA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "7.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "7.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Json": {
+ "type": "Direct",
+ "requested": "[7.0.0, )",
+ "resolved": "7.0.0",
+ "contentHash": "LDNYe3uw76W35Jci+be4LDf2lkQZe0A7EEYQVChFbc509CpZ4Iupod8li4PUXPBhEUOFI/rlQNf5xkzJRQGvtA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "7.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "7.0.0",
+ "Microsoft.Extensions.Configuration.FileExtensions": "7.0.0",
+ "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0",
+ "System.Text.Json": "7.0.0"
+ }
+ },
+ "Microsoft.Extensions.Options.ConfigurationExtensions": {
+ "type": "Direct",
+ "requested": "[7.0.0, )",
+ "resolved": "7.0.0",
+ "contentHash": "95UnxZkkFdXxF6vSrtJsMHCzkDeSMuUWGs2hDT54cX+U5eVajrCJ3qLyQRW+CtpTt5OJ8bmTvpQVHu1DLhH+cA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "7.0.0",
+ "Microsoft.Extensions.Configuration.Binder": "7.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
+ "Microsoft.Extensions.Options": "7.0.0",
+ "Microsoft.Extensions.Primitives": "7.0.0"
+ }
+ },
+ "Microsoft.NET.Test.Sdk": {
+ "type": "Direct",
+ "requested": "[17.8.0, )",
+ "resolved": "17.8.0",
+ "contentHash": "BmTYGbD/YuDHmApIENdoyN1jCk0Rj1fJB0+B/fVekyTdVidr91IlzhqzytiUgaEAzL1ZJcYCme0MeBMYvJVzvw==",
+ "dependencies": {
+ "Microsoft.CodeCoverage": "17.8.0",
+ "Microsoft.TestPlatform.TestHost": "17.8.0"
+ }
+ },
+ "Moq": {
+ "type": "Direct",
+ "requested": "[4.20.69, )",
+ "resolved": "4.20.69",
+ "contentHash": "8P/oAUOL8ZVyXnzBBcgdhTsOD1kQbAWfOcMI7KDQO3HqQtzB/0WYLdnMa4Jefv8nu/MQYiiG0IuoJdvG0v0Nig==",
+ "dependencies": {
+ "Castle.Core": "5.1.1"
+ }
+ },
+ "NBuilder": {
+ "type": "Direct",
+ "requested": "[6.1.0, )",
+ "resolved": "6.1.0",
+ "contentHash": "NtDOtz/yc24t5yNivaGJQ1LHczoaYwNDjI04P7KEFDmbb2h6uL5OJZ5ExKx+wcypK2dBhRj2o1SiLAfj3kc8jw==",
+ "dependencies": {
+ "NETStandard.Library": "1.6.1"
+ }
+ },
+ "xunit": {
+ "type": "Direct",
+ "requested": "[2.6.1, )",
+ "resolved": "2.6.1",
+ "contentHash": "SnTEV7LFf2s3GJua5AJKB/m115jDcWJSG5n02YZS05iezU2QJKjShCsOxlxL8FUO+J7h2/yXGEr+evgpIHc3sA==",
+ "dependencies": {
+ "xunit.analyzers": "1.4.0",
+ "xunit.assert": "2.6.1",
+ "xunit.core": "[2.6.1]"
+ }
+ },
+ "xunit.assert": {
+ "type": "Direct",
+ "requested": "[2.6.1, )",
+ "resolved": "2.6.1",
+ "contentHash": "+4bI81RS88tiYvfsBfC0YsdDd8v7kkLkRtDXmux3YBT8u1afhjdwxwBvkHGgrQ6NPRzE8xZpVGX2iaLkbXvYvg=="
+ },
+ "xunit.extensibility.core": {
+ "type": "Direct",
+ "requested": "[2.6.1, )",
+ "resolved": "2.6.1",
+ "contentHash": "DA4NqcFGLlRxX2zP3QptlQuRoOSdmBkr17ntK29jfRXqScj2fysIhvQvF5DHtDzAEkoRPqZcfR/IRGSItxmRqw==",
+ "dependencies": {
+ "NETStandard.Library": "1.6.1",
+ "xunit.abstractions": "2.0.3"
+ }
+ },
+ "xunit.runner.visualstudio": {
+ "type": "Direct",
+ "requested": "[2.5.3, )",
+ "resolved": "2.5.3",
+ "contentHash": "HFFL6O+QLEOfs555SqHii48ovVa4CqGYanY+B32BjLpPptdE+wEJmCFNXlLHdEOD5LYeayb9EroaUpydGpcybg=="
+ },
+ "Castle.Core": {
+ "type": "Transitive",
+ "resolved": "5.1.1",
+ "contentHash": "rpYtIczkzGpf+EkZgDr9CClTdemhsrwA/W5hMoPjLkRFnXzH44zDLoovXeKtmxb1ykXK9aJVODSpiJml8CTw2g==",
+ "dependencies": {
+ "System.Diagnostics.EventLog": "6.0.0"
+ }
+ },
+ "Microsoft.CodeCoverage": {
+ "type": "Transitive",
+ "resolved": "17.8.0",
+ "contentHash": "KC8SXWbGIdoFVdlxKk9WHccm0llm9HypcHMLUUFabRiTS3SO2fQXNZfdiF3qkEdTJhbRrxhdRxjL4jbtwPq4Ew=="
+ },
+ "Microsoft.Extensions.Configuration.Abstractions": {
+ "type": "Transitive",
+ "resolved": "7.0.0",
+ "contentHash": "f34u2eaqIjNO9YLHBz8rozVZ+TcFiFs0F3r7nUJd7FRkVSxk8u4OpoK226mi49MwexHOR2ibP9MFvRUaLilcQQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "7.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Binder": {
+ "type": "Transitive",
+ "resolved": "7.0.0",
+ "contentHash": "tgU4u7bZsoS9MKVRiotVMAwHtbREHr5/5zSEV+JPhg46+ox47Au84E3D2IacAaB0bk5ePNaNieTlPrfjbbRJkg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "7.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.FileExtensions": {
+ "type": "Transitive",
+ "resolved": "7.0.0",
+ "contentHash": "xk2lRJ1RDuqe57BmgvRPyCt6zyePKUmvT6iuXqiHR+/OIIgWVR8Ff5k2p6DwmqY8a17hx/OnrekEhziEIeQP6Q==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "7.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "7.0.0",
+ "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0",
+ "Microsoft.Extensions.FileProviders.Physical": "7.0.0",
+ "Microsoft.Extensions.Primitives": "7.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "7.0.0",
+ "contentHash": "h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw=="
+ },
+ "Microsoft.Extensions.FileProviders.Abstractions": {
+ "type": "Transitive",
+ "resolved": "7.0.0",
+ "contentHash": "NyawiW9ZT/liQb34k9YqBSNPLuuPkrjMgQZ24Y/xXX1RoiBkLUdPMaQTmxhZ5TYu8ZKZ9qayzil75JX95vGQUg==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "7.0.0"
+ }
+ },
+ "Microsoft.Extensions.FileProviders.Physical": {
+ "type": "Transitive",
+ "resolved": "7.0.0",
+ "contentHash": "K8D2MTR+EtzkbZ8z80LrG7Ur64R7ZZdRLt1J5cgpc/pUWl0C6IkAUapPuK28oionHueCPELUqq0oYEvZfalNdg==",
+ "dependencies": {
+ "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0",
+ "Microsoft.Extensions.FileSystemGlobbing": "7.0.0",
+ "Microsoft.Extensions.Primitives": "7.0.0"
+ }
+ },
+ "Microsoft.Extensions.FileSystemGlobbing": {
+ "type": "Transitive",
+ "resolved": "7.0.0",
+ "contentHash": "2jONjKHiF+E92ynz2ZFcr9OvxIw+rTGMPEH+UZGeHTEComVav93jQUWGkso8yWwVBcEJGcNcZAaqY01FFJcj7w=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "7.0.0",
+ "contentHash": "lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
+ "Microsoft.Extensions.Primitives": "7.0.0"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "7.0.0",
+ "contentHash": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q==",
+ "dependencies": {
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ },
+ "Microsoft.IdentityModel.Abstractions": {
+ "type": "Transitive",
+ "resolved": "7.3.1",
+ "contentHash": "gIw8Sr5ZpuzKFBTfJonh2F54DivTzm5IIK15QB4Y6uE30uQdEO1NnCojTC/b6sWZoZzD0sdBa6SqwMXhucD+nA=="
+ },
+ "Microsoft.IdentityModel.JsonWebTokens": {
+ "type": "Transitive",
+ "resolved": "7.3.1",
+ "contentHash": "mXA6AoaD5uZqtsKghgRiupBhyXNii8p9F2BjNLnDGud0tZLS5+4Fio2YAGjFXhnkc80CqgQ61X5U1gUNnDEoKQ==",
+ "dependencies": {
+ "Microsoft.IdentityModel.Tokens": "7.3.1"
+ }
+ },
+ "Microsoft.IdentityModel.Logging": {
+ "type": "Transitive",
+ "resolved": "7.3.1",
+ "contentHash": "uPt2aiRUCbcOc0Wk+dDCSClFfPNs3S3Z7fmy50MoxJ1mGmtVUDMpyRJeYzZ/16x4rL19T+g2zrzjcWoitp5+gQ==",
+ "dependencies": {
+ "Microsoft.IdentityModel.Abstractions": "7.3.1"
+ }
+ },
+ "Microsoft.IdentityModel.Tokens": {
+ "type": "Transitive",
+ "resolved": "7.3.1",
+ "contentHash": "/c/p8/3CAH706c0ii5uTgSb/8M/jwyuurtdMeKTBeKFU9aA+EZrLu1M8aaS3CSlGaxoxsoaxr4/+KXykgQ4VgQ==",
+ "dependencies": {
+ "Microsoft.IdentityModel.Logging": "7.3.1"
+ }
+ },
+ "Microsoft.NETCore.Platforms": {
+ "type": "Transitive",
+ "resolved": "1.1.0",
+ "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A=="
+ },
+ "Microsoft.NETCore.Targets": {
+ "type": "Transitive",
+ "resolved": "1.1.0",
+ "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg=="
+ },
+ "Microsoft.TestPlatform.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "17.8.0",
+ "contentHash": "AYy6vlpGMfz5kOFq99L93RGbqftW/8eQTqjT9iGXW6s9MRP3UdtY8idJ8rJcjeSja8A18IhIro5YnH3uv1nz4g==",
+ "dependencies": {
+ "NuGet.Frameworks": "6.5.0",
+ "System.Reflection.Metadata": "1.6.0"
+ }
+ },
+ "Microsoft.TestPlatform.TestHost": {
+ "type": "Transitive",
+ "resolved": "17.8.0",
+ "contentHash": "9ivcl/7SGRmOT0YYrHQGohWiT5YCpkmy/UEzldfVisLm6QxbLaK3FAJqZXI34rnRLmqqDCeMQxKINwmKwAPiDw==",
+ "dependencies": {
+ "Microsoft.TestPlatform.ObjectModel": "17.8.0",
+ "Newtonsoft.Json": "13.0.1"
+ }
+ },
+ "Microsoft.Win32.Primitives": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "9ZQKCWxH7Ijp9BfahvL2Zyf1cJIk8XYLF6Yjzr2yi0b2cOut/HQ31qf1ThHAgCc3WiZMdnWcfJCgN82/0UunxA==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "NETStandard.Library": {
+ "type": "Transitive",
+ "resolved": "1.6.1",
+ "contentHash": "WcSp3+vP+yHNgS8EV5J7pZ9IRpeDuARBPN28by8zqff1wJQXm26PVU8L3/fYLBJVU7BtDyqNVWq2KlCVvSSR4A==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.Win32.Primitives": "4.3.0",
+ "System.AppContext": "4.3.0",
+ "System.Collections": "4.3.0",
+ "System.Collections.Concurrent": "4.3.0",
+ "System.Console": "4.3.0",
+ "System.Diagnostics.Debug": "4.3.0",
+ "System.Diagnostics.Tools": "4.3.0",
+ "System.Diagnostics.Tracing": "4.3.0",
+ "System.Globalization": "4.3.0",
+ "System.Globalization.Calendars": "4.3.0",
+ "System.IO": "4.3.0",
+ "System.IO.Compression": "4.3.0",
+ "System.IO.Compression.ZipFile": "4.3.0",
+ "System.IO.FileSystem": "4.3.0",
+ "System.IO.FileSystem.Primitives": "4.3.0",
+ "System.Linq": "4.3.0",
+ "System.Linq.Expressions": "4.3.0",
+ "System.Net.Http": "4.3.0",
+ "System.Net.Primitives": "4.3.0",
+ "System.Net.Sockets": "4.3.0",
+ "System.ObjectModel": "4.3.0",
+ "System.Reflection": "4.3.0",
+ "System.Reflection.Extensions": "4.3.0",
+ "System.Reflection.Primitives": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Runtime.Handles": "4.3.0",
+ "System.Runtime.InteropServices": "4.3.0",
+ "System.Runtime.InteropServices.RuntimeInformation": "4.3.0",
+ "System.Runtime.Numerics": "4.3.0",
+ "System.Security.Cryptography.Algorithms": "4.3.0",
+ "System.Security.Cryptography.Encoding": "4.3.0",
+ "System.Security.Cryptography.Primitives": "4.3.0",
+ "System.Security.Cryptography.X509Certificates": "4.3.0",
+ "System.Text.Encoding": "4.3.0",
+ "System.Text.Encoding.Extensions": "4.3.0",
+ "System.Text.RegularExpressions": "4.3.0",
+ "System.Threading": "4.3.0",
+ "System.Threading.Tasks": "4.3.0",
+ "System.Threading.Timer": "4.3.0",
+ "System.Xml.ReaderWriter": "4.3.0",
+ "System.Xml.XDocument": "4.3.0"
+ }
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
+ "NuGet.Frameworks": {
+ "type": "Transitive",
+ "resolved": "6.5.0",
+ "contentHash": "QWINE2x3MbTODsWT1Gh71GaGb5icBz4chS8VYvTgsBnsi8esgN6wtHhydd7fvToWECYGq7T4cgBBDiKD/363fg=="
+ },
+ "RestSharp": {
+ "type": "Transitive",
+ "resolved": "110.2.0",
+ "contentHash": "FXGw0IMcqY7yO/hzS9QrD3iNswNgb9UxJnxWmfOxmGs4kRlZWqdtBoGPLuhlbgsDzX1RFo4WKui8TGGKXWKalw==",
+ "dependencies": {
+ "System.Text.Json": "7.0.2"
+ }
+ },
+ "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "HdSSp5MnJSsg08KMfZThpuLPJpPwE5hBXvHwoKWosyHHfe8Mh5WKT0ylEOf6yNzX6Ngjxe4Whkafh5q7Ymac4Q=="
+ },
+ "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "+yH1a49wJMy8Zt4yx5RhJrxO/DBDByAiCzNwiETI+1S4mPdCu0OY4djdciC7Vssk0l22wQaDLrXxXkp+3+7bVA=="
+ },
+ "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "c3YNH1GQJbfIPJeCnr4avseugSqPrxwIqzthYyZDN6EuOyNOzq+y2KSUfRcXauya1sF4foESTgwM5e1A8arAKw=="
+ },
+ "runtime.native.System": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "c/qWt2LieNZIj1jGnVNsE2Kl23Ya2aSTBuXMD6V7k9KWr6l16Tqdwq+hJScEpWER9753NWC8h96PaVNY5Ld7Jw==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0"
+ }
+ },
+ "runtime.native.System.IO.Compression": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "INBPonS5QPEgn7naufQFXJEp3zX6L4bwHgJ/ZH78aBTpeNfQMtf7C6VrAFhlq2xxWBveIOWyFzQjJ8XzHMhdOQ==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0"
+ }
+ },
+ "runtime.native.System.Net.Http": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "ZVuZJqnnegJhd2k/PtAbbIcZ3aZeITq3sj06oKfMBSfphW3HDmk/t4ObvbOk/JA/swGR0LNqMksAh/f7gpTROg==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0"
+ }
+ },
+ "runtime.native.System.Security.Cryptography.Apple": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "DloMk88juo0OuOWr56QG7MNchmafTLYWvABy36izkrLI5VledI0rq28KGs1i9wbpeT9NPQrx/wTf8U2vazqQ3Q==",
+ "dependencies": {
+ "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "4.3.0"
+ }
+ },
+ "runtime.native.System.Security.Cryptography.OpenSsl": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "NS1U+700m4KFRHR5o4vo9DSlTmlCKu/u7dtE5sUHVIPB+xpXxYQvgBgA6wEIeCz6Yfn0Z52/72WYsToCEPJnrw==",
+ "dependencies": {
+ "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0",
+ "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0",
+ "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0",
+ "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0",
+ "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0",
+ "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0",
+ "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0",
+ "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0",
+ "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0",
+ "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0"
+ }
+ },
+ "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "b3pthNgxxFcD+Pc0WSEoC0+md3MyhRS6aCEeenvNE3Fdw1HyJ18ZhRFVJJzIeR/O/jpxPboB805Ho0T3Ul7w8A=="
+ },
+ "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "KeLz4HClKf+nFS7p/6Fi/CqyLXh81FpiGzcmuS8DGi9lUqSnZ6Es23/gv2O+1XVGfrbNmviF7CckBpavkBoIFQ=="
+ },
+ "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "kVXCuMTrTlxq4XOOMAysuNwsXWpYeboGddNGpIgNSZmv1b6r/s/DPk0fYMB7Q5Qo4bY68o48jt4T4y5BVecbCQ=="
+ },
+ "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "X7IdhILzr4ROXd8mI1BUCQMSHSQwelUlBjF1JyTKCjXaOGn2fB4EKBxQbCK2VjO3WaWIdlXZL3W6TiIVnrhX4g=="
+ },
+ "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "nyFNiCk/r+VOiIqreLix8yN+q3Wga9+SE8BCgkf+2BwEKiNx6DyvFjCgkfV743/grxv8jHJ8gUK4XEQw7yzRYg=="
+ },
+ "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "ytoewC6wGorL7KoCAvRfsgoJPJbNq+64k2SqW6JcOAebWsFUvCCYgfzQMrnpvPiEl4OrblUlhF2ji+Q1+SVLrQ=="
+ },
+ "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "I8bKw2I8k58Wx7fMKQJn2R8lamboCAiHfHeV/pS65ScKWMMI0+wJkLYlEKvgW1D/XvSl/221clBoR2q9QNNM7A=="
+ },
+ "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "VB5cn/7OzUfzdnC8tqAIMQciVLiq2epm2NrAm1E9OjNRyG4lVhfR61SMcLizejzQP8R8Uf/0l5qOIbUEi+RdEg=="
+ },
+ "System.AppContext": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "fKC+rmaLfeIzUhagxY17Q9siv/sPrjjKcfNg1Ic8IlQkZLipo8ljcaZQu4VtI4Jqbzjc2VTjzGLF6WmsRXAEgA==",
+ "dependencies": {
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Buffers": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "ratu44uTIHgeBeI0dE8DWvmXVBSo4u7ozRZZHOMmK/JPpYyo0dAfgSiHlpiObMQ5lEtEyIXA40sKRYg5J6A8uQ==",
+ "dependencies": {
+ "System.Diagnostics.Debug": "4.3.0",
+ "System.Diagnostics.Tracing": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Threading": "4.3.0"
+ }
+ },
+ "System.Collections": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Collections.Concurrent": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "ztl69Xp0Y/UXCL+3v3tEU+lIy+bvjKNUmopn1wep/a291pVPK7dxBd6T7WnlQqRog+d1a/hSsgRsmFnIBKTPLQ==",
+ "dependencies": {
+ "System.Collections": "4.3.0",
+ "System.Diagnostics.Debug": "4.3.0",
+ "System.Diagnostics.Tracing": "4.3.0",
+ "System.Globalization": "4.3.0",
+ "System.Reflection": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Threading": "4.3.0",
+ "System.Threading.Tasks": "4.3.0"
+ }
+ },
+ "System.Console": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "DHDrIxiqk1h03m6khKWV2X8p/uvN79rgSqpilL6uzpmSfxfU5ng8VcPtW4qsDsQDHiTv6IPV9TmD5M/vElPNLg==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.IO": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Text.Encoding": "4.3.0"
+ }
+ },
+ "System.Diagnostics.Debug": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Diagnostics.DiagnosticSource": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "tD6kosZnTAGdrEa0tZSuFyunMbt/5KYDnHdndJYGqZoNy00XVXyACd5d6KnE1YgYv3ne2CjtAfNXo/fwEhnKUA==",
+ "dependencies": {
+ "System.Collections": "4.3.0",
+ "System.Diagnostics.Tracing": "4.3.0",
+ "System.Reflection": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Threading": "4.3.0"
+ }
+ },
+ "System.Diagnostics.EventLog": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "lcyUiXTsETK2ALsZrX+nWuHSIQeazhqPphLfaRxzdGaG93+0kELqpgEHtwWOlQe7+jSFnKwaCAgL4kjeZCQJnw=="
+ },
+ "System.Diagnostics.Tools": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "UUvkJfSYJMM6x527dJg2VyWPSRqIVB0Z7dbjHst1zmwTXz5CcXSYJFWRpuigfbO1Lf7yfZiIaEUesfnl/g5EyA==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Diagnostics.Tracing": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "rswfv0f/Cqkh78rA5S8eN8Neocz234+emGCtTF3lxPY96F+mmmUen6tbn0glN6PMvlKQb9bPAY5e9u7fgPTkKw==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Globalization": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Globalization.Calendars": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "GUlBtdOWT4LTV3I+9/PJW+56AnnChTaOqqTLFtdmype/L500M2LIyXgmtd9X2P2VOkmJd5c67H5SaC2QcL1bFA==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Globalization": "4.3.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Globalization.Extensions": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "FhKmdR6MPG+pxow6wGtNAWdZh7noIOpdD5TwQ3CprzgIE1bBBoim0vbR1+AWsWjQmU7zXHgQo4TWSP6lCeiWcQ==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "System.Globalization": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Runtime.InteropServices": "4.3.0"
+ }
+ },
+ "System.IdentityModel.Tokens.Jwt": {
+ "type": "Transitive",
+ "resolved": "7.3.1",
+ "contentHash": "iE8biOWyAC1NnYcZGcgXErNACvIQ6Gcmg5s28gsjVbyyYdF9NdKsYzAPAsO3KGK86EQjpToI1AO82XbG8chkzA==",
+ "dependencies": {
+ "Microsoft.IdentityModel.JsonWebTokens": "7.3.1",
+ "Microsoft.IdentityModel.Tokens": "7.3.1"
+ }
+ },
+ "System.IO": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Runtime": "4.3.0",
+ "System.Text.Encoding": "4.3.0",
+ "System.Threading.Tasks": "4.3.0"
+ }
+ },
+ "System.IO.Compression": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "YHndyoiV90iu4iKG115ibkhrG+S3jBm8Ap9OwoUAzO5oPDAWcr0SFwQFm0HjM8WkEZWo0zvLTyLmbvTkW1bXgg==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "System.Buffers": "4.3.0",
+ "System.Collections": "4.3.0",
+ "System.Diagnostics.Debug": "4.3.0",
+ "System.IO": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Runtime.Handles": "4.3.0",
+ "System.Runtime.InteropServices": "4.3.0",
+ "System.Text.Encoding": "4.3.0",
+ "System.Threading": "4.3.0",
+ "System.Threading.Tasks": "4.3.0",
+ "runtime.native.System": "4.3.0",
+ "runtime.native.System.IO.Compression": "4.3.0"
+ }
+ },
+ "System.IO.Compression.ZipFile": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "G4HwjEsgIwy3JFBduZ9quBkAu+eUwjIdJleuNSgmUojbH6O3mlvEIme+GHx/cLlTAPcrnnL7GqvB9pTlWRfhOg==",
+ "dependencies": {
+ "System.Buffers": "4.3.0",
+ "System.IO": "4.3.0",
+ "System.IO.Compression": "4.3.0",
+ "System.IO.FileSystem": "4.3.0",
+ "System.IO.FileSystem.Primitives": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Text.Encoding": "4.3.0"
+ }
+ },
+ "System.IO.FileSystem": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "3wEMARTnuio+ulnvi+hkRNROYwa1kylvYahhcLk4HSoVdl+xxTFVeVlYOfLwrDPImGls0mDqbMhrza8qnWPTdA==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.IO": "4.3.0",
+ "System.IO.FileSystem.Primitives": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Handles": "4.3.0",
+ "System.Text.Encoding": "4.3.0",
+ "System.Threading.Tasks": "4.3.0"
+ }
+ },
+ "System.IO.FileSystem.Primitives": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "6QOb2XFLch7bEc4lIcJH49nJN2HV+OC3fHDgsLVsBVBk3Y4hFAnOBGzJ2lUu7CyDDFo9IBWkSsnbkT6IBwwiMw==",
+ "dependencies": {
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Linq": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "5DbqIUpsDp0dFftytzuMmc0oeMdQwjcP/EWxsksIz/w1TcFRkZ3yKKz0PqiYFMmEwPSWw+qNVqD7PJ889JzHbw==",
+ "dependencies": {
+ "System.Collections": "4.3.0",
+ "System.Diagnostics.Debug": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0"
+ }
+ },
+ "System.Linq.Expressions": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "PGKkrd2khG4CnlyJwxwwaWWiSiWFNBGlgXvJpeO0xCXrZ89ODrQ6tjEWS/kOqZ8GwEOUATtKtzp1eRgmYNfclg==",
+ "dependencies": {
+ "System.Collections": "4.3.0",
+ "System.Diagnostics.Debug": "4.3.0",
+ "System.Globalization": "4.3.0",
+ "System.IO": "4.3.0",
+ "System.Linq": "4.3.0",
+ "System.ObjectModel": "4.3.0",
+ "System.Reflection": "4.3.0",
+ "System.Reflection.Emit": "4.3.0",
+ "System.Reflection.Emit.ILGeneration": "4.3.0",
+ "System.Reflection.Emit.Lightweight": "4.3.0",
+ "System.Reflection.Extensions": "4.3.0",
+ "System.Reflection.Primitives": "4.3.0",
+ "System.Reflection.TypeExtensions": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Threading": "4.3.0"
+ }
+ },
+ "System.Net.Http": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "sYg+FtILtRQuYWSIAuNOELwVuVsxVyJGWQyOnlAzhV4xvhyFnON1bAzYYC+jjRW8JREM45R0R5Dgi8MTC5sEwA==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "System.Collections": "4.3.0",
+ "System.Diagnostics.Debug": "4.3.0",
+ "System.Diagnostics.DiagnosticSource": "4.3.0",
+ "System.Diagnostics.Tracing": "4.3.0",
+ "System.Globalization": "4.3.0",
+ "System.Globalization.Extensions": "4.3.0",
+ "System.IO": "4.3.0",
+ "System.IO.FileSystem": "4.3.0",
+ "System.Net.Primitives": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Runtime.Handles": "4.3.0",
+ "System.Runtime.InteropServices": "4.3.0",
+ "System.Security.Cryptography.Algorithms": "4.3.0",
+ "System.Security.Cryptography.Encoding": "4.3.0",
+ "System.Security.Cryptography.OpenSsl": "4.3.0",
+ "System.Security.Cryptography.Primitives": "4.3.0",
+ "System.Security.Cryptography.X509Certificates": "4.3.0",
+ "System.Text.Encoding": "4.3.0",
+ "System.Threading": "4.3.0",
+ "System.Threading.Tasks": "4.3.0",
+ "runtime.native.System": "4.3.0",
+ "runtime.native.System.Net.Http": "4.3.0",
+ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0"
+ }
+ },
+ "System.Net.Primitives": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "qOu+hDwFwoZPbzPvwut2qATe3ygjeQBDQj91xlsaqGFQUI5i4ZnZb8yyQuLGpDGivEPIt8EJkd1BVzVoP31FXA==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Handles": "4.3.0"
+ }
+ },
+ "System.Net.Sockets": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "m6icV6TqQOAdgt5N/9I5KNpjom/5NFtkmGseEH+AK/hny8XrytLH3+b5M8zL/Ycg3fhIocFpUMyl/wpFnVRvdw==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.IO": "4.3.0",
+ "System.Net.Primitives": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Threading.Tasks": "4.3.0"
+ }
+ },
+ "System.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "bdX+80eKv9bN6K4N+d77OankKHGn6CH711a6fcOpMQu2Fckp/Ft4L/kW9WznHpyR0NRAvJutzOMHNNlBGvxQzQ==",
+ "dependencies": {
+ "System.Collections": "4.3.0",
+ "System.Diagnostics.Debug": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Threading": "4.3.0"
+ }
+ },
+ "System.Reflection": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.IO": "4.3.0",
+ "System.Reflection.Primitives": "4.3.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Reflection.Emit": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "228FG0jLcIwTVJyz8CLFKueVqQK36ANazUManGaJHkO0icjiIypKW7YLWLIWahyIkdh5M7mV2dJepllLyA1SKg==",
+ "dependencies": {
+ "System.IO": "4.3.0",
+ "System.Reflection": "4.3.0",
+ "System.Reflection.Emit.ILGeneration": "4.3.0",
+ "System.Reflection.Primitives": "4.3.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Reflection.Emit.ILGeneration": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "59tBslAk9733NXLrUJrwNZEzbMAcu8k344OYo+wfSVygcgZ9lgBdGIzH/nrg3LYhXceynyvTc8t5/GD4Ri0/ng==",
+ "dependencies": {
+ "System.Reflection": "4.3.0",
+ "System.Reflection.Primitives": "4.3.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Reflection.Emit.Lightweight": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "oadVHGSMsTmZsAF864QYN1t1QzZjIcuKU3l2S9cZOwDdDueNTrqq1yRj7koFfIGEnKpt6NjpL3rOzRhs4ryOgA==",
+ "dependencies": {
+ "System.Reflection": "4.3.0",
+ "System.Reflection.Emit.ILGeneration": "4.3.0",
+ "System.Reflection.Primitives": "4.3.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Reflection.Extensions": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Reflection": "4.3.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Reflection.Metadata": {
+ "type": "Transitive",
+ "resolved": "1.6.0",
+ "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ=="
+ },
+ "System.Reflection.Primitives": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Reflection.TypeExtensions": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "7u6ulLcZbyxB5Gq0nMkQttcdBTx57ibzw+4IOXEfR+sXYQoHvjW5LTLyNr8O22UIMrqYbchJQJnos4eooYzYJA==",
+ "dependencies": {
+ "System.Reflection": "4.3.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Resources.ResourceManager": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Globalization": "4.3.0",
+ "System.Reflection": "4.3.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Runtime": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0"
+ }
+ },
+ "System.Runtime.CompilerServices.Unsafe": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
+ },
+ "System.Runtime.Extensions": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Runtime.Handles": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Runtime.InteropServices": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Reflection": "4.3.0",
+ "System.Reflection.Primitives": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Handles": "4.3.0"
+ }
+ },
+ "System.Runtime.InteropServices.RuntimeInformation": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw==",
+ "dependencies": {
+ "System.Reflection": "4.3.0",
+ "System.Reflection.Extensions": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.InteropServices": "4.3.0",
+ "System.Threading": "4.3.0",
+ "runtime.native.System": "4.3.0"
+ }
+ },
+ "System.Runtime.Numerics": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "yMH+MfdzHjy17l2KESnPiF2dwq7T+xLnSJar7slyimAkUh/gTrS9/UQOtv7xarskJ2/XDSNvfLGOBQPjL7PaHQ==",
+ "dependencies": {
+ "System.Globalization": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0"
+ }
+ },
+ "System.Security.Cryptography.Algorithms": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "W1kd2Y8mYSCgc3ULTAZ0hOP2dSdG5YauTb1089T0/kRcN2MpSAW1izOFROrJgxSlMn3ArsgHXagigyi+ibhevg==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "System.Collections": "4.3.0",
+ "System.IO": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Runtime.Handles": "4.3.0",
+ "System.Runtime.InteropServices": "4.3.0",
+ "System.Runtime.Numerics": "4.3.0",
+ "System.Security.Cryptography.Encoding": "4.3.0",
+ "System.Security.Cryptography.Primitives": "4.3.0",
+ "System.Text.Encoding": "4.3.0",
+ "runtime.native.System.Security.Cryptography.Apple": "4.3.0",
+ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0"
+ }
+ },
+ "System.Security.Cryptography.Cng": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "03idZOqFlsKRL4W+LuCpJ6dBYDUWReug6lZjBa3uJWnk5sPCUXckocevTaUA8iT/MFSrY/2HXkOt753xQ/cf8g==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "System.IO": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Runtime.Handles": "4.3.0",
+ "System.Runtime.InteropServices": "4.3.0",
+ "System.Security.Cryptography.Algorithms": "4.3.0",
+ "System.Security.Cryptography.Encoding": "4.3.0",
+ "System.Security.Cryptography.Primitives": "4.3.0",
+ "System.Text.Encoding": "4.3.0"
+ }
+ },
+ "System.Security.Cryptography.Csp": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "X4s/FCkEUnRGnwR3aSfVIkldBmtURMhmexALNTwpjklzxWU7yjMk7GHLKOZTNkgnWnE0q7+BCf9N2LVRWxewaA==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "System.IO": "4.3.0",
+ "System.Reflection": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Runtime.Handles": "4.3.0",
+ "System.Runtime.InteropServices": "4.3.0",
+ "System.Security.Cryptography.Algorithms": "4.3.0",
+ "System.Security.Cryptography.Encoding": "4.3.0",
+ "System.Security.Cryptography.Primitives": "4.3.0",
+ "System.Text.Encoding": "4.3.0",
+ "System.Threading": "4.3.0"
+ }
+ },
+ "System.Security.Cryptography.Encoding": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "1DEWjZZly9ae9C79vFwqaO5kaOlI5q+3/55ohmq/7dpDyDfc8lYe7YVxJUZ5MF/NtbkRjwFRo14yM4OEo9EmDw==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "System.Collections": "4.3.0",
+ "System.Collections.Concurrent": "4.3.0",
+ "System.Linq": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Runtime.Handles": "4.3.0",
+ "System.Runtime.InteropServices": "4.3.0",
+ "System.Security.Cryptography.Primitives": "4.3.0",
+ "System.Text.Encoding": "4.3.0",
+ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0"
+ }
+ },
+ "System.Security.Cryptography.OpenSsl": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "h4CEgOgv5PKVF/HwaHzJRiVboL2THYCou97zpmhjghx5frc7fIvlkY1jL+lnIQyChrJDMNEXS6r7byGif8Cy4w==",
+ "dependencies": {
+ "System.Collections": "4.3.0",
+ "System.IO": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Runtime.Handles": "4.3.0",
+ "System.Runtime.InteropServices": "4.3.0",
+ "System.Runtime.Numerics": "4.3.0",
+ "System.Security.Cryptography.Algorithms": "4.3.0",
+ "System.Security.Cryptography.Encoding": "4.3.0",
+ "System.Security.Cryptography.Primitives": "4.3.0",
+ "System.Text.Encoding": "4.3.0",
+ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0"
+ }
+ },
+ "System.Security.Cryptography.Primitives": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "7bDIyVFNL/xKeFHjhobUAQqSpJq9YTOpbEs6mR233Et01STBMXNAc/V+BM6dwYGc95gVh/Zf+iVXWzj3mE8DWg==",
+ "dependencies": {
+ "System.Diagnostics.Debug": "4.3.0",
+ "System.Globalization": "4.3.0",
+ "System.IO": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Threading": "4.3.0",
+ "System.Threading.Tasks": "4.3.0"
+ }
+ },
+ "System.Security.Cryptography.X509Certificates": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "t2Tmu6Y2NtJ2um0RtcuhP7ZdNNxXEgUm2JeoA/0NvlMjAhKCnM1NX07TDl3244mVp3QU6LPEhT3HTtH1uF7IYw==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "System.Collections": "4.3.0",
+ "System.Diagnostics.Debug": "4.3.0",
+ "System.Globalization": "4.3.0",
+ "System.Globalization.Calendars": "4.3.0",
+ "System.IO": "4.3.0",
+ "System.IO.FileSystem": "4.3.0",
+ "System.IO.FileSystem.Primitives": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Runtime.Handles": "4.3.0",
+ "System.Runtime.InteropServices": "4.3.0",
+ "System.Runtime.Numerics": "4.3.0",
+ "System.Security.Cryptography.Algorithms": "4.3.0",
+ "System.Security.Cryptography.Cng": "4.3.0",
+ "System.Security.Cryptography.Csp": "4.3.0",
+ "System.Security.Cryptography.Encoding": "4.3.0",
+ "System.Security.Cryptography.OpenSsl": "4.3.0",
+ "System.Security.Cryptography.Primitives": "4.3.0",
+ "System.Text.Encoding": "4.3.0",
+ "System.Threading": "4.3.0",
+ "runtime.native.System": "4.3.0",
+ "runtime.native.System.Net.Http": "4.3.0",
+ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0"
+ }
+ },
+ "System.Text.Encoding": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Text.Encoding.Extensions": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "YVMK0Bt/A43RmwizJoZ22ei2nmrhobgeiYwFzC4YAN+nue8RF6djXDMog0UCn+brerQoYVyaS+ghy9P/MUVcmw==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Runtime": "4.3.0",
+ "System.Text.Encoding": "4.3.0"
+ }
+ },
+ "System.Text.Encodings.Web": {
+ "type": "Transitive",
+ "resolved": "7.0.0",
+ "contentHash": "OP6umVGxc0Z0MvZQBVigj4/U31Pw72ITihDWP9WiWDm+q5aoe0GaJivsfYGq53o6dxH7DcXWiCTl7+0o2CGdmg==",
+ "dependencies": {
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ },
+ "System.Text.Json": {
+ "type": "Transitive",
+ "resolved": "7.0.2",
+ "contentHash": "/LZf/JrGyilojqwpaywb+sSz8Tew7ij4K/Sk+UW8AKfAK7KRhR6mKpKtTm06cYA7bCpGTWfYksIW+mVsdxPegQ==",
+ "dependencies": {
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0",
+ "System.Text.Encodings.Web": "7.0.0"
+ }
+ },
+ "System.Text.RegularExpressions": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "RpT2DA+L660cBt1FssIE9CAGpLFdFPuheB7pLpKpn6ZXNby7jDERe8Ua/Ne2xGiwLVG2JOqziiaVCGDon5sKFA==",
+ "dependencies": {
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Threading": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==",
+ "dependencies": {
+ "System.Runtime": "4.3.0",
+ "System.Threading.Tasks": "4.3.0"
+ }
+ },
+ "System.Threading.Tasks": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Threading.Tasks.Extensions": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "npvJkVKl5rKXrtl1Kkm6OhOUaYGEiF9wFbppFRWSMoApKzt2PiPHT2Bb8a5sAWxprvdOAtvaARS9QYMznEUtug==",
+ "dependencies": {
+ "System.Collections": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Threading.Tasks": "4.3.0"
+ }
+ },
+ "System.Threading.Timer": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "Z6YfyYTCg7lOZjJzBjONJTFKGN9/NIYKSxhU5GRd+DTwHSZyvWp1xuI5aR+dLg+ayyC5Xv57KiY4oJ0tMO89fQ==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "Microsoft.NETCore.Targets": "1.1.0",
+ "System.Runtime": "4.3.0"
+ }
+ },
+ "System.Xml.ReaderWriter": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "GrprA+Z0RUXaR4N7/eW71j1rgMnEnEVlgii49GZyAjTH7uliMnrOU3HNFBr6fEDBCJCIdlVNq9hHbaDR621XBA==",
+ "dependencies": {
+ "System.Collections": "4.3.0",
+ "System.Diagnostics.Debug": "4.3.0",
+ "System.Globalization": "4.3.0",
+ "System.IO": "4.3.0",
+ "System.IO.FileSystem": "4.3.0",
+ "System.IO.FileSystem.Primitives": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Runtime.InteropServices": "4.3.0",
+ "System.Text.Encoding": "4.3.0",
+ "System.Text.Encoding.Extensions": "4.3.0",
+ "System.Text.RegularExpressions": "4.3.0",
+ "System.Threading.Tasks": "4.3.0",
+ "System.Threading.Tasks.Extensions": "4.3.0"
+ }
+ },
+ "System.Xml.XDocument": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "5zJ0XDxAIg8iy+t4aMnQAu0MqVbqyvfoUVl1yDV61xdo3Vth45oA2FoY4pPkxYAH5f8ixpmTqXeEIya95x0aCQ==",
+ "dependencies": {
+ "System.Collections": "4.3.0",
+ "System.Diagnostics.Debug": "4.3.0",
+ "System.Diagnostics.Tools": "4.3.0",
+ "System.Globalization": "4.3.0",
+ "System.IO": "4.3.0",
+ "System.Reflection": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Text.Encoding": "4.3.0",
+ "System.Threading": "4.3.0",
+ "System.Xml.ReaderWriter": "4.3.0"
+ }
+ },
+ "xunit.abstractions": {
+ "type": "Transitive",
+ "resolved": "2.0.3",
+ "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg=="
+ },
+ "xunit.analyzers": {
+ "type": "Transitive",
+ "resolved": "1.4.0",
+ "contentHash": "7ljnTJfFjz5zK+Jf0h2dd2QOSO6UmFizXsojv/x4QX7TU5vEgtKZPk9RvpkiuUqg2bddtNZufBoKQalsi7djfA=="
+ },
+ "xunit.core": {
+ "type": "Transitive",
+ "resolved": "2.6.1",
+ "contentHash": "Ru0POZXVYwa/G3/tS3TO3Yug/P+08RPeDkuepTmywNjfICYwHHY9zJBoxdeziZ0OintLtLKUMOBcC6VJzjqhwg==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.6.1]",
+ "xunit.extensibility.execution": "[2.6.1]"
+ }
+ },
+ "xunit.extensibility.execution": {
+ "type": "Transitive",
+ "resolved": "2.6.1",
+ "contentHash": "sLKPQKuEQhRuhVuLiYEkRdUcwCfp+BIKds3r0JL8AYvOWRmVYYKWYouuYzPjmeUF6iEGC9CHCVz/NF1+wv+Mag==",
+ "dependencies": {
+ "NETStandard.Library": "1.6.1",
+ "xunit.extensibility.core": "[2.6.1]"
+ }
+ },
+ "descope": {
+ "type": "Project",
+ "dependencies": {
+ "Newtonsoft.Json": "[13.0.3, )",
+ "RestSharp": "[110.2.0, )",
+ "System.IdentityModel.Tokens.Jwt": "[7.3.1, )"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Descope.Test/xunit.runner.json b/Descope.Test/xunit.runner.json
new file mode 100644
index 0000000..dd80f43
--- /dev/null
+++ b/Descope.Test/xunit.runner.json
@@ -0,0 +1,5 @@
+{
+ "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
+ "parallelizeAssembly": false,
+ "parallelizeTestCollections": false
+}
diff --git a/Descope.sln b/Descope.sln
new file mode 100644
index 0000000..1d748c6
--- /dev/null
+++ b/Descope.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.7.34221.43
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Descope", "..\descope-dotnet\Descope\Descope.csproj", "{4B7D16FE-6007-4F53-84BA-44C5BA8CAD75}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Descope.Test", "..\descope-dotnet\Descope.Test\Descope.Test.csproj", "{A1CD983B-6231-4B0E-A07F-B5A5EE14A16F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {4B7D16FE-6007-4F53-84BA-44C5BA8CAD75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4B7D16FE-6007-4F53-84BA-44C5BA8CAD75}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4B7D16FE-6007-4F53-84BA-44C5BA8CAD75}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4B7D16FE-6007-4F53-84BA-44C5BA8CAD75}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A1CD983B-6231-4B0E-A07F-B5A5EE14A16F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A1CD983B-6231-4B0E-A07F-B5A5EE14A16F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A1CD983B-6231-4B0E-A07F-B5A5EE14A16F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A1CD983B-6231-4B0E-A07F-B5A5EE14A16F}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {B336F720-C2FB-425E-A428-0F4F747DD7D2}
+ EndGlobalSection
+EndGlobal
diff --git a/Descope/Descope.csproj b/Descope/Descope.csproj
new file mode 100644
index 0000000..2337c01
--- /dev/null
+++ b/Descope/Descope.csproj
@@ -0,0 +1,29 @@
+
+
+
+ net6.0
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Descope/Descope.sln b/Descope/Descope.sln
new file mode 100644
index 0000000..f2896a3
--- /dev/null
+++ b/Descope/Descope.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.7.34221.43
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Descope", "Descope.csproj", "{B2EBA0EC-66DF-484A-A140-1937AF5F90CF}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Descope.Test", "..\Descope.Test\Descope.Test.csproj", "{2342D0A7-D9EE-4A31-9BA9-0294147938B4}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B2EBA0EC-66DF-484A-A140-1937AF5F90CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B2EBA0EC-66DF-484A-A140-1937AF5F90CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B2EBA0EC-66DF-484A-A140-1937AF5F90CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B2EBA0EC-66DF-484A-A140-1937AF5F90CF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2342D0A7-D9EE-4A31-9BA9-0294147938B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2342D0A7-D9EE-4A31-9BA9-0294147938B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2342D0A7-D9EE-4A31-9BA9-0294147938B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2342D0A7-D9EE-4A31-9BA9-0294147938B4}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {FEFAFD62-DCCD-488B-9ED9-9A7DDBF9CEFA}
+ EndGlobalSection
+EndGlobal
diff --git a/Descope/DescopeClient.cs b/Descope/DescopeClient.cs
new file mode 100644
index 0000000..53660e0
--- /dev/null
+++ b/Descope/DescopeClient.cs
@@ -0,0 +1,26 @@
+using Descope.Internal.Management;
+using Descope.Internal.Auth;
+
+namespace Descope
+{
+ public class DescopeClient
+ {
+ public IAuthentication Auth { get; }
+ public IManagement Management { get; }
+
+ public DescopeClient(DescopeConfig descopeConfig)
+ {
+ var httpClient = new Internal.HttpClient(descopeConfig);
+ var managementKey = descopeConfig.ManagementKey ?? "";
+
+ Auth = new Authentication(httpClient);
+ Management = new Management(httpClient, managementKey);
+ }
+ }
+
+ public static class SdkInfo
+ {
+ public static string Name { get; } = "dotnet";
+ public static string Version { get; } = "0.1.0";
+ }
+}
diff --git a/Descope/Exception/DescopeException.cs b/Descope/Exception/DescopeException.cs
new file mode 100644
index 0000000..340adec
--- /dev/null
+++ b/Descope/Exception/DescopeException.cs
@@ -0,0 +1,41 @@
+using System.Text.Json.Serialization;
+
+namespace Descope
+{
+ [Serializable]
+ public class DescopeException : ApplicationException
+ {
+ public string? ErrorCode { get; set; }
+ public string? ErrorDescription { get; set; }
+ public string? ErrorMessage { get; set; }
+
+ public DescopeException(string msg) : base(msg) { }
+
+ public DescopeException(ErrorDetails errorDetails) : base(message: errorDetails.ExceptionMessage)
+ {
+ ErrorCode = errorDetails.ErrorCode;
+ ErrorDescription = errorDetails.ErrorDescription;
+ ErrorMessage = errorDetails.ErrorMessage;
+ }
+ }
+
+ public class ErrorDetails
+ {
+ [JsonPropertyName("errorCode")]
+ public string ErrorCode { get; set; }
+
+ [JsonPropertyName("errorDescription")]
+ public string ErrorDescription { get; set; }
+ [JsonPropertyName("errorMessage")]
+ public string? ErrorMessage { get; set; }
+ public ErrorDetails(string errorCode, string errorDescription, string? errorMessage)
+ {
+ ErrorCode = errorCode;
+ ErrorDescription = errorDescription;
+ ErrorMessage = errorMessage;
+ }
+
+ public string ExceptionMessage { get => $"[{ErrorCode}]: {ErrorDescription}{(ErrorMessage != null ? $" ({ErrorMessage})" : "")}"; }
+
+ }
+}
diff --git a/Descope/Internal/Authentication/Authentication.cs b/Descope/Internal/Authentication/Authentication.cs
new file mode 100644
index 0000000..47e3a67
--- /dev/null
+++ b/Descope/Internal/Authentication/Authentication.cs
@@ -0,0 +1,284 @@
+using Microsoft.IdentityModel.JsonWebTokens;
+using Microsoft.IdentityModel.Tokens;
+using System.Security.Cryptography;
+using System.Text.Json.Serialization;
+
+namespace Descope.Internal.Auth
+{
+ public class Authentication : IAuthentication
+ {
+ public IOtp Otp { get => _otp; }
+
+ private readonly Otp _otp;
+
+ private readonly IHttpClient _httpClient;
+ private readonly JsonWebTokenHandler _jsonWebTokenHandler = new();
+ private readonly Dictionary> _securityKeys = new();
+
+ private const string ClaimPermissions = "permissions";
+ private const string ClaimRoles = "roles";
+
+ public Authentication(IHttpClient httpClient)
+ {
+ _httpClient = httpClient;
+ _otp = new Otp(httpClient);
+ }
+
+ public async Task ValidateSession(string sessionJwt)
+ {
+ if (string.IsNullOrEmpty(sessionJwt)) throw new DescopeException("sessionJwt empty");
+ var token = await ValidateToken(sessionJwt) ?? throw new DescopeException("Session invalid");
+ return token;
+ }
+
+ public async Task RefreshSession(string refreshJwt)
+ {
+ if (string.IsNullOrEmpty(refreshJwt)) throw new DescopeException("refreshJwt empty");
+ var refreshToken = await ValidateToken(refreshJwt) ?? throw new DescopeException("Refresh token invalid");
+ var response = await _httpClient.Post(Routes.AuthRefresh, refreshJwt);
+ try
+ {
+ return new Token(_jsonWebTokenHandler.ReadJsonWebToken(response.SessionJwt))
+ {
+ RefreshExpiration = refreshToken.Expiration
+ };
+ }
+ catch
+ {
+ throw new DescopeException("Unable to parse refreshed session jwt");
+ }
+ }
+
+ public async Task ValidateAndRefreshSession(string sessionJwt, string refreshJwt)
+ {
+ if (string.IsNullOrEmpty(sessionJwt) && string.IsNullOrEmpty(refreshJwt)) throw new DescopeException("Both sessionJwt and refreshJwt are empty");
+ if (!string.IsNullOrEmpty(sessionJwt))
+ {
+ try { return await ValidateSession(sessionJwt); }
+ catch { }
+ }
+ if (string.IsNullOrEmpty(refreshJwt)) throw new DescopeException("Cannot refresh session with empty refresh JWT");
+ return await RefreshSession(refreshJwt);
+ }
+
+ public async Task ExchangeAccessKey(string accessKey, AccessKeyLoginOptions? loginOptions = null)
+ {
+ if (string.IsNullOrEmpty(accessKey)) throw new DescopeException("access key missing");
+ var response = await _httpClient.Post(Routes.AuthAccessKeyExchange, accessKey, new { loginOptions });
+ return new Token(_jsonWebTokenHandler.ReadJsonWebToken(response.SessionJwt)) ?? throw new DescopeException("Failed to parse exchanged token");
+ }
+
+ public bool ValidatePermissions(Token token, List permissions, string? tenant)
+ {
+ return ValidateAgainstClaims(token, ClaimPermissions, permissions, tenant);
+ }
+
+ public List GetMatchedPermissions(Token token, List permissions, string? tenant)
+ {
+ return GetMatchedClaimValues(token, ClaimPermissions, permissions, tenant);
+ }
+
+ public bool ValidateRoles(Token token, List roles, string? tenant)
+ {
+ return ValidateAgainstClaims(token, ClaimRoles, roles, tenant);
+ }
+
+ public List GetMatchedRoles(Token token, List roles, string? tenant)
+ {
+ return GetMatchedClaimValues(token, ClaimRoles, roles, tenant);
+ }
+
+ public async Task SelectTenant(string tenant, string refreshJwt)
+ {
+ if (string.IsNullOrEmpty(refreshJwt)) throw new DescopeException("refreshJwt empty");
+ var token = await ValidateToken(refreshJwt) ?? throw new DescopeException("invalid refreshJwt");
+ var body = new { tenant };
+ var response = await _httpClient.Post(Routes.AuthSelectTenant, refreshJwt, body);
+ return AuthResponseToSession(response, token);
+ }
+
+ public async Task LogOut(string refreshJwt)
+ {
+ if (string.IsNullOrEmpty(refreshJwt)) throw new DescopeException("refreshJwt empty");
+ _ = await ValidateToken(refreshJwt) ?? throw new DescopeException("invalid refreshJwt");
+ await _httpClient.Post