Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Auth0.ManagementApi/Models/Client/ClientBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,4 +222,10 @@ public abstract class ClientBase
/// </summary>
[JsonProperty("token_quota")]
public TokenQuota TokenQuota { get; set; }

/// <summary>
/// Native to Web SSO configuration.
/// </summary>
[JsonProperty("session_transfer")]
public SessionTransfer? SessionTransfer { get; set; }
}
32 changes: 32 additions & 0 deletions src/Auth0.ManagementApi/Models/Client/DeviceBindingType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Runtime.Serialization;

namespace Auth0.ManagementApi.Models;

/// <summary>
/// Indicates whether device binding security should be enforced for the app.
/// If set to 'ip', the app will enforce device binding by IP, meaning that consumption of session_token must be
/// done from the same IP of the issuer. Likewise, if set to 'asn', device binding is enforced by ASN, meaning
/// consumption of session_token must be done from the same ASN as the issuer.
/// If set to 'null', device binding is not enforced.
/// </summary>
public enum DeviceBindingType
{
/// <summary>
/// Ip
/// </summary>
[EnumMember(Value = "ip")]
Ip,

/// <summary>
/// Asn
/// </summary>
[EnumMember(Value = "asn")]
Asn,

/// <summary>
/// None
/// </summary>
[EnumMember(Value = "none")]
None,

}
56 changes: 56 additions & 0 deletions src/Auth0.ManagementApi/Models/Client/SessionTransfer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace Auth0.ManagementApi.Models;

/// <summary>
/// Native to Web SSO configuration.
/// </summary>
public class SessionTransfer
{
/// <summary>
/// Indicates whether an app can issue a session_token through Token Exchange.
/// If set to 'false', the app will not be able to issue a session_token.
/// </summary>
[JsonProperty("can_create_session_transfer_token")]
public bool? CanCreateSessionTransferToken { get; set; }

/// <summary>
/// Indicates whether an app can create a session from a session_token received via indicated methods.
/// </summary>
[JsonProperty("allowed_authentication_methods")]
public string[]? AllowedAuthenticationMethods { get; set; }

/// <summary>
/// Indicates whether device binding security should be enforced for the app.
/// If set to 'ip', the app will enforce device binding by IP, meaning that consumption of session_token must be
/// done from the same IP of the issuer.
/// Likewise, if set to 'asn', device binding is enforced by ASN, meaning consumption of session_token must be
/// done from the same ASN as the issuer.
/// If set to 'null', device binding is not enforced.
/// </summary>
/// <remarks>Possible values: [ip, asn, none]</remarks>
[JsonConverter(typeof(StringEnumConverter))]
[JsonProperty("enforce_device_binding")]
public DeviceBindingType? EnforceDeviceBinding { get; set; }

/// <summary>
/// Indicates whether Refresh Tokens are allowed to be issued when authenticating with a session_transfer_token.
/// </summary>
[JsonProperty("allow_refresh_token")]
public bool? AllowRefreshToken { get; set; }

/// <summary>
/// Indicates whether Refresh Tokens created during a native-to-web session are tied to that session's lifetime.
/// This determines if such refresh tokens should be automatically revoked when their corresponding sessions are.
/// </summary>
[JsonProperty("enforce_online_refresh_tokens")]
public bool? EnforceOnlineRefreshTokens { get; set; }

/// <summary>
/// Indicates whether revoking the parent Refresh Token that initiated a Native to Web flow and was used to issue
/// a Session Transfer Token should trigger a cascade revocation affecting its dependent child entities.
/// </summary>
[JsonProperty("enforce_cascade_revocation")]
public bool? EnforceCascadeRevocation { get; set; }
}
42 changes: 42 additions & 0 deletions tests/Auth0.ManagementApi.IntegrationTests/ClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,15 @@ public async Task Test_client_crud_sequence()
PerHour = 10,
Enforce = true
}
},
SessionTransfer = new SessionTransfer()
{
AllowedAuthenticationMethods = ["cookie"],
AllowRefreshToken = true,
CanCreateSessionTransferToken = true,
EnforceCascadeRevocation = true,
EnforceDeviceBinding = DeviceBindingType.Ip,
EnforceOnlineRefreshTokens = true
}
};
var newClientResponse = await fixture.ApiClient.Clients.CreateAsync(newClientRequest);
Expand All @@ -140,6 +149,15 @@ public async Task Test_client_crud_sequence()
newClientResponse.ComplianceLevel.Should().Be(ComplianceLevel.FAPI1_ADV_PKJ_PAR);
newClientResponse.RequireProofOfPossession.Should().BeTrue();
newClientResponse.TokenQuota.Should().BeEquivalentTo(newClientRequest.TokenQuota);

// Session transfer assertions
newClientResponse.SessionTransfer.Should().NotBeNull();
newClientResponse.SessionTransfer?.AllowRefreshToken.Should().BeTrue();
newClientResponse.SessionTransfer?.EnforceCascadeRevocation.Should().BeTrue();
newClientResponse.SessionTransfer?.EnforceOnlineRefreshTokens.Should().BeTrue();
newClientResponse.SessionTransfer?.CanCreateSessionTransferToken.Should().BeTrue();
newClientResponse.SessionTransfer?.AllowedAuthenticationMethods.Should().BeEquivalentTo(["cookie"]);
newClientResponse.SessionTransfer?.EnforceDeviceBinding.Should().Be(DeviceBindingType.Ip);

string prop1 = newClientResponse.ClientMetaData.Prop1;
prop1.Should().Be("1");
Expand Down Expand Up @@ -177,6 +195,15 @@ public async Task Test_client_crud_sequence()
{
Enforce = false
}
},
SessionTransfer = new SessionTransfer()
{
AllowedAuthenticationMethods = ["query"],
AllowRefreshToken = false,
CanCreateSessionTransferToken = false,
EnforceCascadeRevocation = false,
EnforceDeviceBinding = DeviceBindingType.None,
EnforceOnlineRefreshTokens = false
}
};

Expand Down Expand Up @@ -206,6 +233,14 @@ public async Task Test_client_crud_sequence()
updateClientResponse.ComplianceLevel.Should().Be(ComplianceLevel.NONE);
updateClientResponse.RequireProofOfPossession.Should().BeFalse();
updateClientResponse.TokenQuota.Should().BeEquivalentTo(updateClientRequest.TokenQuota);
// Session transfer assertions
updateClientResponse.SessionTransfer.Should().NotBeNull();
updateClientResponse.SessionTransfer?.AllowRefreshToken.Should().BeFalse();
updateClientResponse.SessionTransfer?.EnforceCascadeRevocation.Should().BeFalse();
updateClientResponse.SessionTransfer?.EnforceOnlineRefreshTokens.Should().BeFalse();
updateClientResponse.SessionTransfer?.CanCreateSessionTransferToken.Should().BeFalse();
updateClientResponse.SessionTransfer?.AllowedAuthenticationMethods.Should().BeEquivalentTo(["query"]);
updateClientResponse.SessionTransfer?.EnforceDeviceBinding.Should().Be(DeviceBindingType.None);

// Get a single client
var client = await fixture.ApiClient.Clients.GetAsync(newClientResponse.ClientId);
Expand All @@ -218,6 +253,13 @@ public async Task Test_client_crud_sequence()
client.SignedRequestObject.Required.Should().BeFalse();
client.ComplianceLevel.Should().Be(ComplianceLevel.NONE);
client.TokenQuota.ClientCredentials.Enforce.Should().Be(false);
client.SessionTransfer.Should().NotBeNull();
client.SessionTransfer?.AllowRefreshToken.Should().BeFalse();
client.SessionTransfer?.EnforceCascadeRevocation.Should().BeFalse();
client.SessionTransfer?.EnforceOnlineRefreshTokens.Should().BeFalse();
client.SessionTransfer?.CanCreateSessionTransferToken.Should().BeFalse();
client.SessionTransfer?.AllowedAuthenticationMethods.Should().BeEquivalentTo(["query"]);
client.SessionTransfer?.EnforceDeviceBinding.Should().Be(DeviceBindingType.None);

// Delete the client, and ensure we get exception when trying to fetch client again
await fixture.ApiClient.Clients.DeleteAsync(client.ClientId);
Expand Down
Loading