diff --git a/sandbox/OpenIddict.Sandbox.WinForms.Client/Worker.cs b/sandbox/OpenIddict.Sandbox.WinForms.Client/Worker.cs
index 10aed3f9..7d6ec529 100644
--- a/sandbox/OpenIddict.Sandbox.WinForms.Client/Worker.cs
+++ b/sandbox/OpenIddict.Sandbox.WinForms.Client/Worker.cs
@@ -27,7 +27,7 @@ public class Worker : IHostedService
// in HKEY_CLASSES_ROOT (in this case, it should be added by a dedicated installer).
//
// Alternatively, the application can be packaged and use windows.protocol to
- // register the protocol handler/custom URI scheme with the operation system.
+ // register the protocol handler/custom URI scheme with the operating system.
using var root = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Classes\\com.openiddict.sandbox.winforms.client");
root.SetValue(string.Empty, "URL:com.openiddict.sandbox.winforms.client");
root.SetValue("URL Protocol", string.Empty);
diff --git a/sandbox/OpenIddict.Sandbox.Wpf.Client/Worker.cs b/sandbox/OpenIddict.Sandbox.Wpf.Client/Worker.cs
index 027cc21e..9ec65a01 100644
--- a/sandbox/OpenIddict.Sandbox.Wpf.Client/Worker.cs
+++ b/sandbox/OpenIddict.Sandbox.Wpf.Client/Worker.cs
@@ -27,7 +27,7 @@ public class Worker : IHostedService
// in HKEY_CLASSES_ROOT (in this case, it should be added by a dedicated installer).
//
// Alternatively, the application can be packaged and use windows.protocol to
- // register the protocol handler/custom URI scheme with the operation system.
+ // register the protocol handler/custom URI scheme with the operating system.
using var root = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Classes\\com.openiddict.sandbox.wpf.client");
root.SetValue(string.Empty, "URL:com.openiddict.sandbox.wpf.client");
root.SetValue("URL Protocol", string.Empty);
diff --git a/src/OpenIddict.Abstractions/OpenIddictResources.resx b/src/OpenIddict.Abstractions/OpenIddictResources.resx
index 42d13a24..3368d8c2 100644
--- a/src/OpenIddict.Abstractions/OpenIddictResources.resx
+++ b/src/OpenIddict.Abstractions/OpenIddictResources.resx
@@ -1669,7 +1669,7 @@ To apply post-logout redirection responses, create a class implementing 'IOpenId
An explicit grant type must be attached when specifying a specific response type (except when using the special response_type=none value).
- AS web authentication sessions are only supported on iOS 12.0 and higher.
+ AS web authentication sessions are only supported on iOS 12.0+/macOS 10.15+/Mac Catalyst 12.0+ and require using an OS-specific target framework moniker on macOS (e.g 'net8.0-macos15.0').
The current UI window cannot be resolved.
@@ -1678,7 +1678,7 @@ To apply post-logout redirection responses, create a class implementing 'IOpenId
An unknown error occurred while trying to start an AS web authentication session.
- The generic version of the OpenIddict.Client.SystemIntegration package cannot be used on this platform. Make sure your application is referencing the correct version by using the appropriate OS-specific TFM (e.g on macOS, 'net8.0-macos10.15').
+ The portable version of the OpenIddict.Client.SystemIntegration package cannot be used on Android, iOS and Mac Catalyst. Make sure your application is referencing the correct version by using the appropriate OS-specific TFM (e.g on iOS, 'net8.0-ios18.0').
An HTTP redirect_uri or post_logout_redirect_uri cannot be used when using AS web authentication sessions. Make sure you're using a custom protocol scheme for all the callback URIs attached to the client registration. Alternatively, you can register an associated domain and use an HTTPS redirect_uri or post_logout_redirect_uri pointing to that domain (supported only on iOS 17.4+, Mac Catalyst 17.4+ and macOS 14.4+).
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationBuilder.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationBuilder.cs
index f3cac42e..866b0742 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationBuilder.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationBuilder.cs
@@ -121,7 +121,7 @@ public sealed class OpenIddictClientSystemIntegrationBuilder
/// The .
public OpenIddictClientSystemIntegrationBuilder SetAllowedEmbeddedWebServerPorts(params int[] ports)
{
- if (Array.Exists(ports, static port => port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort))
+ if (Array.Exists(ports, static port => port is < IPEndPoint.MinPort or > IPEndPoint.MaxPort))
{
throw new ArgumentOutOfRangeException(nameof(ports));
}
@@ -278,25 +278,15 @@ public sealed class OpenIddictClientSystemIntegrationBuilder
return Configure(options => options.PipeSecurity = security);
}
- ///
- /// Determines whether the specified object is equal to the current object.
- ///
- /// The object to compare with the current object.
- /// if the specified object is equal to the current object; otherwise, false.
+ ///
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object? obj) => base.Equals(obj);
- ///
- /// Serves as the default hash function.
- ///
- /// A hash code for the current object.
+ ///
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode() => base.GetHashCode();
- ///
- /// Returns a string that represents the current object.
- ///
- /// A string that represents the current object.
+ ///
[EditorBrowsable(EditorBrowsableState.Never)]
public override string? ToString() => base.ToString();
}
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationConfiguration.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationConfiguration.cs
index 247beddf..1aa1a383 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationConfiguration.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationConfiguration.cs
@@ -88,19 +88,16 @@ public sealed class OpenIddictClientSystemIntegrationConfiguration : IConfigureO
}
#if !SUPPORTS_ANDROID
- // When running on Android, iOS, Mac Catalyst or macOS, ensure the version compiled for
- // these platforms is used to prevent the generic/non-OS specific TFM from being used.
+ // When running on Android, iOS or Mac Catalyst, ensure the version compiled for these platforms
+ // is used to prevent the generic/non-OS specific TFM from being used as launching the system
+ // browser cannot be done using Process.Start() and requires using OS-specific APIs that are
+ // not available on the portable version of the OpenIddict.Client.SystemIntegration package.
if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("android")))
{
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0449));
}
#endif
-#if !SUPPORTS_APPKIT
- if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
- {
- throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0449));
- }
-#endif
+
#if !SUPPORTS_UIKIT
if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("ios")) ||
RuntimeInformation.IsOSPlatform(OSPlatform.Create("maccatalyst")))
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationExtensions.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationExtensions.cs
index 0e4981af..4c4a3a6d 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationExtensions.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationExtensions.cs
@@ -43,19 +43,16 @@ public static class OpenIddictClientSystemIntegrationExtensions
}
#if !SUPPORTS_ANDROID
- // When running on Android, iOS, Mac Catalyst or macOS, ensure the version compiled for
- // these platforms is used to prevent the generic/non-OS specific TFM from being used.
+ // When running on Android, iOS or Mac Catalyst, ensure the version compiled for these platforms
+ // is used to prevent the generic/non-OS specific TFM from being used as launching the system
+ // browser cannot be done using Process.Start() and requires using OS-specific APIs that are
+ // not available on the portable version of the OpenIddict.Client.SystemIntegration package.
if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("android")))
{
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0449));
}
#endif
-#if !SUPPORTS_APPKIT
- if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
- {
- throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0449));
- }
-#endif
+
#if !SUPPORTS_UIKIT
if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("ios")) ||
RuntimeInformation.IsOSPlatform(OSPlatform.Create("maccatalyst")))
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs
index a77e63ab..c557f256 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs
@@ -5,7 +5,6 @@
*/
using System.Collections.Immutable;
-using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
@@ -105,8 +104,6 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Transaction.Request is not null, SR.GetResourceString(SR.ID4008));
-
#if SUPPORTS_AUTHENTICATION_SERVICES && SUPPORTS_FOUNDATION
if (string.IsNullOrEmpty(context.RedirectUri) ||
!Uri.TryCreate(context.RedirectUri, UriKind.Absolute, out Uri? uri))
@@ -239,7 +236,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
NSUrl CreateUrl() => new(OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.AuthorizationEndpoint, UriKind.Absolute),
- parameters: context.Transaction.Request.GetParameters().ToDictionary(
+ parameters: context.Request.GetParameters().ToDictionary(
parameter => parameter.Key,
parameter => new StringValues((string?[]?) parameter.Value))).AbsoluteUri);
@@ -341,8 +338,6 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Transaction.Request is not null, SR.GetResourceString(SR.ID4008));
-
#if SUPPORTS_ANDROID && SUPPORTS_ANDROIDX_BROWSER
if (string.IsNullOrEmpty(context.RedirectUri))
{
@@ -369,7 +364,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
// custom activity responsible for handling callback URIs pointing to a custom scheme.
intent.LaunchUrl(Application.Context, NativeUri.Parse(OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.AuthorizationEndpoint, UriKind.Absolute),
- parameters: context.Transaction.Request.GetParameters().ToDictionary(
+ parameters: context.Request.GetParameters().ToDictionary(
parameter => parameter.Key,
parameter => new StringValues((string?[]?) parameter.Value))).AbsoluteUri)!);
@@ -414,8 +409,6 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Transaction.Request is not null, SR.GetResourceString(SR.ID4008));
-
#if SUPPORTS_WINDOWS_RUNTIME
if (string.IsNullOrEmpty(context.RedirectUri))
{
@@ -454,7 +447,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
options : WebAuthenticationOptions.None,
requestUri : OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.AuthorizationEndpoint, UriKind.Absolute),
- parameters: context.Transaction.Request.GetParameters().ToDictionary(
+ parameters: context.Request.GetParameters().ToDictionary(
parameter => parameter.Key,
parameter => new StringValues((string?[]?) parameter.Value))),
callbackUri: new Uri(context.RedirectUri, UriKind.Absolute)))
@@ -571,11 +564,9 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Transaction.Request is not null, SR.GetResourceString(SR.ID4008));
-
var uri = OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.AuthorizationEndpoint, UriKind.Absolute),
- parameters: context.Transaction.Request.GetParameters().ToDictionary(
+ parameters: context.Request.GetParameters().ToDictionary(
parameter => parameter.Key,
parameter => new StringValues((string?[]?) parameter.Value)));
@@ -614,6 +605,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
}
}
+ // On Android, iOS and Mac Catalyst, Process.Start() is not supported and
+ // OS-specific/non-portable APIs must be used to launch the system browser.
#if SUPPORTS_ANDROID
if (OperatingSystem.IsAndroid() && TryLaunchBrowserWithGenericIntent(uri))
{
@@ -621,20 +614,26 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
return;
}
#endif
-
#if SUPPORTS_UIKIT
if ((OperatingSystem.IsIOS() || OperatingSystem.IsMacCatalyst()) && await TryLaunchBrowserWithUIApplicationAsync(uri))
{
context.HandleRequest();
return;
}
-#elif SUPPORTS_APPKIT
+#endif
+#if SUPPORTS_APPKIT
if (OperatingSystem.IsMacOS() && TryLaunchBrowserWithNSWorkspace(uri))
{
context.HandleRequest();
return;
}
#endif
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && await TryLaunchBrowserWithOpenAsync(uri))
+ {
+ context.HandleRequest();
+ return;
+ }
+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && await TryLaunchBrowserWithXdgOpenAsync(uri))
{
context.HandleRequest();
@@ -670,8 +669,6 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Transaction.Response is not null, SR.GetResourceString(SR.ID4007));
-
// This handler only applies to HTTP listener requests. If the HTTP context cannot be resolved,
// this may indicate that the request was incorrectly processed by another server stack.
var response = context.Transaction.GetHttpListenerContext()?.Response ??
@@ -683,7 +680,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
// Return a message indicating whether the authentication process
// succeeded or failed and that will be visible by the user.
- var buffer = Encoding.UTF8.GetBytes(context.Transaction.Response.Error switch
+ var buffer = Encoding.UTF8.GetBytes(context.Response.Error switch
{
null or { Length: 0 } => "Login completed. Please return to the application.",
Errors.AccessDenied => "Authorization denied. Please return to the application.",
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs
index 3b978e65..910d0b65 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs
@@ -5,7 +5,6 @@
*/
using System.Collections.Immutable;
-using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
@@ -105,8 +104,6 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Transaction.Request is not null, SR.GetResourceString(SR.ID4008));
-
#if SUPPORTS_AUTHENTICATION_SERVICES && SUPPORTS_FOUNDATION
if (string.IsNullOrEmpty(context.PostLogoutRedirectUri) ||
!Uri.TryCreate(context.PostLogoutRedirectUri, UriKind.Absolute, out Uri? uri))
@@ -239,7 +236,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
NSUrl CreateUrl() => new(OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.EndSessionEndpoint, UriKind.Absolute),
- parameters: context.Transaction.Request.GetParameters().ToDictionary(
+ parameters: context.Request.GetParameters().ToDictionary(
parameter => parameter.Key,
parameter => new StringValues((string?[]?) parameter.Value))).AbsoluteUri);
@@ -341,8 +338,6 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Transaction.Request is not null, SR.GetResourceString(SR.ID4008));
-
#if SUPPORTS_ANDROID && SUPPORTS_ANDROIDX_BROWSER
if (string.IsNullOrEmpty(context.PostLogoutRedirectUri))
{
@@ -369,7 +364,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
// custom activity responsible for handling callback URIs pointing to a custom scheme.
intent.LaunchUrl(Application.Context, NativeUri.Parse(OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.EndSessionEndpoint, UriKind.Absolute),
- parameters: context.Transaction.Request.GetParameters().ToDictionary(
+ parameters: context.Request.GetParameters().ToDictionary(
parameter => parameter.Key,
parameter => new StringValues((string?[]?) parameter.Value))).AbsoluteUri)!);
@@ -414,8 +409,6 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Transaction.Request is not null, SR.GetResourceString(SR.ID4008));
-
#if SUPPORTS_WINDOWS_RUNTIME
if (string.IsNullOrEmpty(context.PostLogoutRedirectUri))
{
@@ -454,7 +447,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
options : WebAuthenticationOptions.None,
requestUri : OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.EndSessionEndpoint, UriKind.Absolute),
- parameters: context.Transaction.Request.GetParameters().ToDictionary(
+ parameters: context.Request.GetParameters().ToDictionary(
parameter => parameter.Key,
parameter => new StringValues((string?[]?) parameter.Value))),
callbackUri: new Uri(context.PostLogoutRedirectUri, UriKind.Absolute)))
@@ -571,11 +564,9 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Transaction.Request is not null, SR.GetResourceString(SR.ID4008));
-
var uri = OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.EndSessionEndpoint, UriKind.Absolute),
- parameters: context.Transaction.Request.GetParameters().ToDictionary(
+ parameters: context.Request.GetParameters().ToDictionary(
parameter => parameter.Key,
parameter => new StringValues((string?[]?) parameter.Value)));
@@ -614,6 +605,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
}
}
+ // On Android, iOS and Mac Catalyst, Process.Start() is not supported and
+ // OS-specific/non-portable APIs must be used to launch the system browser.
#if SUPPORTS_ANDROID
if (OperatingSystem.IsAndroid() && TryLaunchBrowserWithGenericIntent(uri))
{
@@ -621,20 +614,26 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
return;
}
#endif
-
#if SUPPORTS_UIKIT
if ((OperatingSystem.IsIOS() || OperatingSystem.IsMacCatalyst()) && await TryLaunchBrowserWithUIApplicationAsync(uri))
{
context.HandleRequest();
return;
}
-#elif SUPPORTS_APPKIT
+#endif
+#if SUPPORTS_APPKIT
if (OperatingSystem.IsMacOS() && TryLaunchBrowserWithNSWorkspace(uri))
{
context.HandleRequest();
return;
}
#endif
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && await TryLaunchBrowserWithOpenAsync(uri))
+ {
+ context.HandleRequest();
+ return;
+ }
+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && await TryLaunchBrowserWithXdgOpenAsync(uri))
{
context.HandleRequest();
@@ -670,8 +669,6 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
- Debug.Assert(context.Transaction.Response is not null, SR.GetResourceString(SR.ID4007));
-
// This handler only applies to HTTP listener requests. If the HTTP context cannot be resolved,
// this may indicate that the request was incorrectly processed by another server stack.
var response = context.Transaction.GetHttpListenerContext()?.Response ??
@@ -683,7 +680,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
// Return a message indicating whether the sign-out process
// succeeded or failed and that will be visible by the user.
- var buffer = Encoding.UTF8.GetBytes(context.Transaction.Response.Error switch
+ var buffer = Encoding.UTF8.GetBytes(context.Response.Error switch
{
null or { Length: 0 } => "Logout completed. Please return to the application.",
Errors.AccessDenied => "Logout denied. Please return to the application.",
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs
index 770baed3..da1de7f9 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs
@@ -109,7 +109,7 @@ public static class OpenIddictClientSystemIntegrationHelpers
[SupportedOSPlatformGuard("maccatalyst13.1")]
[SupportedOSPlatformGuard("macos10.15")]
internal static bool IsASWebAuthenticationSessionSupported()
-#if SUPPORTS_OPERATING_SYSTEM_VERSIONS_COMPARISON
+#if SUPPORTS_AUTHENTICATION_SERVICES && SUPPORTS_OPERATING_SYSTEM_VERSIONS_COMPARISON
=> OperatingSystem.IsIOSVersionAtLeast(12) ||
OperatingSystem.IsMacCatalystVersionAtLeast(13) ||
OperatingSystem.IsMacOSVersionAtLeast(10, 15);
@@ -124,7 +124,7 @@ public static class OpenIddictClientSystemIntegrationHelpers
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[SupportedOSPlatformGuard("android21.0")]
internal static bool IsCustomTabsIntentSupported()
-#if SUPPORTS_OPERATING_SYSTEM_VERSIONS_COMPARISON
+#if SUPPORTS_ANDROIDX_BROWSER && SUPPORTS_OPERATING_SYSTEM_VERSIONS_COMPARISON
=> OperatingSystem.IsAndroidVersionAtLeast(21);
#else
=> false;
@@ -142,7 +142,12 @@ public static class OpenIddictClientSystemIntegrationHelpers
// guard that will prevent the WinRT projections from being loaded by the runtime on
// platforms that don't support it. Since OpenIddict declares Windows 10 1809 as the
// oldest supported version in the package, it is also used for the runtime check.
- internal static bool IsWindowsRuntimeSupported() => IsWindowsVersionAtLeast(10, 0, 17763);
+ internal static bool IsWindowsRuntimeSupported()
+#if SUPPORTS_WINDOWS_RUNTIME
+ => IsWindowsVersionAtLeast(10, 0, 17763);
+#else
+ => false;
+#endif
///
/// Determines whether WinRT app instance activation is supported on this platform.
@@ -394,11 +399,10 @@ public static class OpenIddictClientSystemIntegrationHelpers
};
///
- /// Starts the system browser using ShellExecute.
+ /// Starts the system browser using the operating system shell.
///
/// The to use.
/// if the browser could be started, otherwise.
- [SupportedOSPlatform("linux")]
[SupportedOSPlatform("windows")]
internal static async ValueTask TryLaunchBrowserWithShellExecuteAsync(Uri uri)
{
@@ -495,7 +499,40 @@ public static class OpenIddictClientSystemIntegrationHelpers
#endif
///
- /// Starts the system browser using xdg-open.
+ /// Starts the system browser using the "open" executable.
+ ///
+ /// The to use.
+ /// if the browser could be started, otherwise.
+ [SupportedOSPlatform("macos")]
+ internal static async ValueTask TryLaunchBrowserWithOpenAsync(Uri uri)
+ {
+ try
+ {
+ await Task.Run(() => Process.Start(new ProcessStartInfo
+ {
+ FileName = "/usr/bin/open",
+ Arguments = uri.AbsoluteUri,
+ UseShellExecute = false,
+
+ // Note: children processes always inherit the standard input/output/error handles of the
+ // parent process by default. To ensure the messages logged by the system browser are not
+ // written to the stdio/stderr of the current process, the streams are always redirected.
+ RedirectStandardError = true,
+ RedirectStandardInput = true,
+ RedirectStandardOutput = true
+ }));
+
+ return true;
+ }
+
+ catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Starts the system browser using the "xdg-open" executable.
///
/// The to use.
/// if the browser could be started, otherwise.
@@ -510,9 +547,9 @@ public static class OpenIddictClientSystemIntegrationHelpers
Arguments = uri.AbsoluteUri,
UseShellExecute = false,
- // Note: on some Linux distributions, xdg-open is known to propagate errors
- // and warnings written to the standard error stream to the parent process.
- // To avoid that, the streams are redirected to this instance and ignored.
+ // Note: children processes always inherit the standard input/output/error handles of the
+ // parent process by default. To ensure the messages logged by the system browser are not
+ // written to the stdio/stderr of the current process, the streams are always redirected.
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true
@@ -521,7 +558,7 @@ public static class OpenIddictClientSystemIntegrationHelpers
return true;
}
- catch (UnauthorizedAccessException)
+ catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
return false;
}
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHttpListener.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHttpListener.cs
index 25ec5949..fae04e37 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHttpListener.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHttpListener.cs
@@ -116,7 +116,7 @@ public sealed class OpenIddictClientSystemIntegrationHttpListener : BackgroundSe
Stack? exceptions = null;
- for (var port = IPEndPoint.MinPort; port <= IPEndPoint.MaxPort; port++)
+ for (var port = IPEndPoint.MinPort; port is <= IPEndPoint.MaxPort; port++)
{
cancellationToken.ThrowIfCancellationRequested();