diff --git a/Directory.Build.props b/Directory.Build.props
index 33a9154d..b1467cd0 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -7,7 +7,7 @@
true
preview
true
- $(NoWarn);CS1591;NU5118;NU5128;xUnit2002
+ $(NoWarn);CS1591;NETSDK1206;NU5118;NU5128;xUnit2002
NU1901;NU1902;NU1903;NU1904
enable
enable
@@ -33,6 +33,31 @@
+
+ true
+
+ true
+
+
+ true
+
net461;
net472;
@@ -45,19 +70,14 @@
net8.0
-
- net8.0-ios
+ Condition=" '$(NetCoreIOSTargetFrameworks)' == '' And '$(SupportsIOSPlatformTargeting)' == 'true' ">
+ net8.0-ios12.0;
+ net8.0-ios13.0
-
+
net6.0-windows7.0;
net6.0-windows10.0.17763;
net7.0-windows7.0;
@@ -71,18 +91,14 @@
netstandard2.1
-
+ Condition=" '$(UniversalWindowsPlatformTargetFrameworks)' == '' And '$(SupportsUniversalWindowsPlatformTargeting)' == 'true' ">
uap10.0.17763
+
+ 12.0
+ 7.0
+ 7.0
@@ -115,6 +131,15 @@
$(_ComputedOfficialBuildId)
+
+ false
+ false
+ false
+ false
+ false
+ false
+
+
true
true
diff --git a/Directory.Build.targets b/Directory.Build.targets
index 6c77786a..f9fcb2a1 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -130,6 +130,13 @@
$(DefineConstants);SUPPORTS_UIKIT
+
+ $(DefineConstants);SUPPORTS_PRESENTATION_CONTEXT_PROVIDER
+
+
+
+
diff --git a/OpenIddict.sln b/OpenIddict.sln
index aaaaea70..b281b36c 100644
--- a/OpenIddict.sln
+++ b/OpenIddict.sln
@@ -157,6 +157,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIddict.Sandbox.WinForms
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIddict.Sandbox.Console.Client", "sandbox\OpenIddict.Sandbox.Console.Client\OpenIddict.Sandbox.Console.Client.csproj", "{819CD7AA-01FD-4369-BABF-5DFCB7E94068}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenIddict.Sandbox.Maui.Client", "sandbox\OpenIddict.Sandbox.Maui.Client\OpenIddict.Sandbox.Maui.Client.csproj", "{CD5EE836-ED56-48E3-B3B6-8D74C7C859B9}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -383,6 +385,12 @@ Global
{819CD7AA-01FD-4369-BABF-5DFCB7E94068}.Debug|Any CPU.Build.0 = Debug|Any CPU
{819CD7AA-01FD-4369-BABF-5DFCB7E94068}.Release|Any CPU.ActiveCfg = Release|Any CPU
{819CD7AA-01FD-4369-BABF-5DFCB7E94068}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CD5EE836-ED56-48E3-B3B6-8D74C7C859B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CD5EE836-ED56-48E3-B3B6-8D74C7C859B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CD5EE836-ED56-48E3-B3B6-8D74C7C859B9}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {CD5EE836-ED56-48E3-B3B6-8D74C7C859B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CD5EE836-ED56-48E3-B3B6-8D74C7C859B9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CD5EE836-ED56-48E3-B3B6-8D74C7C859B9}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -443,6 +451,7 @@ Global
{D0C56832-6557-4CC1-91EA-7B31B18BEE7A} = {F47D1283-0EE9-4728-8026-58405C29B786}
{35997586-8AAB-4EE5-A022-3E5BD12746CE} = {F47D1283-0EE9-4728-8026-58405C29B786}
{819CD7AA-01FD-4369-BABF-5DFCB7E94068} = {F47D1283-0EE9-4728-8026-58405C29B786}
+ {CD5EE836-ED56-48E3-B3B6-8D74C7C859B9} = {F47D1283-0EE9-4728-8026-58405C29B786}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A710059F-0466-4D48-9B3A-0EF4F840B616}
diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/OpenIddict.Sandbox.AspNetCore.Client.csproj b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/OpenIddict.Sandbox.AspNetCore.Client.csproj
index f97b3a4b..93de5836 100644
--- a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/OpenIddict.Sandbox.AspNetCore.Client.csproj
+++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/OpenIddict.Sandbox.AspNetCore.Client.csproj
@@ -2,7 +2,6 @@
net48;net8.0
- false
disable
diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/OpenIddict.Sandbox.AspNetCore.Server.csproj b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/OpenIddict.Sandbox.AspNetCore.Server.csproj
index 07d99588..bea71b8c 100644
--- a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/OpenIddict.Sandbox.AspNetCore.Server.csproj
+++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/OpenIddict.Sandbox.AspNetCore.Server.csproj
@@ -2,8 +2,6 @@
net48;net8.0
- false
- false
false
disable
diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs
index aaf8556c..07e73800 100644
--- a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs
+++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs
@@ -103,6 +103,47 @@ public class Worker : IHostedService
});
}
+ if (await manager.FindByClientIdAsync("maui") is null)
+ {
+ await manager.CreateAsync(new OpenIddictApplicationDescriptor
+ {
+ ApplicationType = ApplicationTypes.Native,
+ ClientId = "maui",
+ ClientType = ClientTypes.Public,
+ ConsentType = ConsentTypes.Systematic,
+ DisplayName = "MAUI client application",
+ DisplayNames =
+ {
+ [CultureInfo.GetCultureInfo("fr-FR")] = "Application cliente MAUI"
+ },
+ PostLogoutRedirectUris =
+ {
+ new Uri("com.openiddict.sandbox.maui.client:/callback/logout/local")
+ },
+ RedirectUris =
+ {
+ new Uri("com.openiddict.sandbox.maui.client:/callback/login/local")
+ },
+ Permissions =
+ {
+ Permissions.Endpoints.Authorization,
+ Permissions.Endpoints.Logout,
+ Permissions.Endpoints.Token,
+ Permissions.GrantTypes.AuthorizationCode,
+ Permissions.GrantTypes.RefreshToken,
+ Permissions.ResponseTypes.Code,
+ Permissions.Scopes.Email,
+ Permissions.Scopes.Profile,
+ Permissions.Scopes.Roles,
+ Permissions.Prefixes.Scope + "demo_api"
+ },
+ Requirements =
+ {
+ Requirements.Features.ProofKeyForCodeExchange
+ }
+ });
+ }
+
if (await manager.FindByClientIdAsync("mvc") is null)
{
await manager.CreateAsync(new OpenIddictApplicationDescriptor
diff --git a/sandbox/OpenIddict.Sandbox.Console.Client/OpenIddict.Sandbox.Console.Client.csproj b/sandbox/OpenIddict.Sandbox.Console.Client/OpenIddict.Sandbox.Console.Client.csproj
index b6c184db..738601fe 100644
--- a/sandbox/OpenIddict.Sandbox.Console.Client/OpenIddict.Sandbox.Console.Client.csproj
+++ b/sandbox/OpenIddict.Sandbox.Console.Client/OpenIddict.Sandbox.Console.Client.csproj
@@ -3,8 +3,6 @@
Exe
net48;net8.0
- false
- false
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/App.xaml b/sandbox/OpenIddict.Sandbox.Maui.Client/App.xaml
new file mode 100644
index 00000000..7a653d33
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/App.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/App.xaml.cs b/sandbox/OpenIddict.Sandbox.Maui.Client/App.xaml.cs
new file mode 100644
index 00000000..42de8c84
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/App.xaml.cs
@@ -0,0 +1,13 @@
+#if IOS || WINDOWS
+namespace OpenIddict.Sandbox.Maui.Client;
+
+public partial class App : Application
+{
+ public App()
+ {
+ InitializeComponent();
+
+ MainPage = new AppShell();
+ }
+}
+#endif
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/AppShell.xaml b/sandbox/OpenIddict.Sandbox.Maui.Client/AppShell.xaml
new file mode 100644
index 00000000..aac5eadd
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/AppShell.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/AppShell.xaml.cs b/sandbox/OpenIddict.Sandbox.Maui.Client/AppShell.xaml.cs
new file mode 100644
index 00000000..b3c46f73
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/AppShell.xaml.cs
@@ -0,0 +1,8 @@
+#if IOS || WINDOWS
+namespace OpenIddict.Sandbox.Maui.Client;
+
+public partial class AppShell : Shell
+{
+ public AppShell() => InitializeComponent();
+}
+#endif
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/MainPage.xaml b/sandbox/OpenIddict.Sandbox.Maui.Client/MainPage.xaml
new file mode 100644
index 00000000..3db3b890
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/MainPage.xaml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/MainPage.xaml.cs b/sandbox/OpenIddict.Sandbox.Maui.Client/MainPage.xaml.cs
new file mode 100644
index 00000000..c42065fc
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/MainPage.xaml.cs
@@ -0,0 +1,149 @@
+#if IOS || WINDOWS
+using OpenIddict.Abstractions;
+using OpenIddict.Client;
+using static OpenIddict.Abstractions.OpenIddictConstants;
+using static OpenIddict.Abstractions.OpenIddictExceptions;
+using static OpenIddict.Client.WebIntegration.OpenIddictClientWebIntegrationConstants;
+
+namespace OpenIddict.Sandbox.Maui.Client;
+
+public partial class MainPage : ContentPage
+{
+ private readonly OpenIddictClientService _service;
+
+ public MainPage(OpenIddictClientService service)
+ {
+ _service = service ?? throw new ArgumentNullException(nameof(service));
+
+ InitializeComponent();
+ }
+
+ private async void OnLocalLoginButtonClicked(object sender, EventArgs e)
+ => await LogInAsync("Local");
+
+ private async void OnLocalLoginWithGitHubButtonClicked(object sender, EventArgs e)
+ => await LogInAsync("Local", new()
+ {
+ [Parameters.IdentityProvider] = Providers.GitHub
+ });
+
+ private async void OnLocalLogoutButtonClicked(object sender, EventArgs e)
+ => await LogOutAsync("Local");
+
+ private async void OnTwitterLoginButtonClicked(object sender, EventArgs e)
+ => await LogInAsync(Providers.Twitter);
+
+ private async Task LogInAsync(string provider, Dictionary? parameters = null)
+ {
+ // Disable the buttons to prevent concurrent operations.
+ LocalLogin.IsEnabled = false;
+ LocalLoginWithGitHub.IsEnabled = false;
+ LocalLogout.IsEnabled = false;
+ TwitterLogin.IsEnabled = false;
+
+ try
+ {
+ using var source = new CancellationTokenSource(delay: TimeSpan.FromSeconds(90));
+
+ try
+ {
+ // Ask OpenIddict to initiate the authentication flow (typically, by starting the system browser).
+ var result = await _service.ChallengeInteractivelyAsync(new()
+ {
+ AdditionalAuthorizationRequestParameters = parameters,
+ CancellationToken = source.Token,
+ ProviderName = provider
+ });
+
+ // Wait for the user to complete the authorization process.
+ var principal = (await _service.AuthenticateInteractivelyAsync(new()
+ {
+ Nonce = result.Nonce
+ })).Principal;
+
+ await DisplayAlert("Authentication successful", $"Welcome, {principal.FindFirst(Claims.Name)!.Value}.", "OK");
+ }
+
+ catch (OperationCanceledException)
+ {
+ await DisplayAlert("Authentication timed out", "The authentication process was aborted.", "OK");
+ }
+
+ catch (ProtocolException exception) when (exception.Error is Errors.AccessDenied)
+ {
+ await DisplayAlert("Authorization denied", "The authorization was denied by the end user.", "OK");
+ }
+
+ catch
+ {
+ await DisplayAlert("Authentication failed", "An error occurred while trying to authenticate the user.", "OK");
+ }
+ }
+
+ finally
+ {
+ // Re-enable the buttons to allow starting a new operation.
+ LocalLogin.IsEnabled = true;
+ LocalLoginWithGitHub.IsEnabled = true;
+ LocalLogout.IsEnabled = true;
+ TwitterLogin.IsEnabled = true;
+ }
+ }
+
+ private async Task LogOutAsync(string provider, Dictionary? parameters = null)
+ {
+ // Disable the buttons to prevent concurrent operations.
+ LocalLogin.IsEnabled = false;
+ LocalLoginWithGitHub.IsEnabled = false;
+ LocalLogout.IsEnabled = false;
+ TwitterLogin.IsEnabled = false;
+
+ try
+ {
+ using var source = new CancellationTokenSource(delay: TimeSpan.FromSeconds(90));
+
+ try
+ {
+ // Ask OpenIddict to initiate the logout flow (typically, by starting the system browser).
+ var result = await _service.SignOutInteractivelyAsync(new()
+ {
+ AdditionalLogoutRequestParameters = parameters,
+ CancellationToken = source.Token,
+ ProviderName = provider
+ });
+
+ // Wait for the user to complete the logout process and authenticate the callback request.
+ //
+ // Note: in this case, only the claims contained in the state token can be resolved since
+ // the authorization server doesn't return any other user identity during a logout dance.
+ await _service.AuthenticateInteractivelyAsync(new()
+ {
+ CancellationToken = source.Token,
+ Nonce = result.Nonce
+ });
+
+ await DisplayAlert("Logout demand successful", "The user was successfully logged out from the local server.", "OK");
+ }
+
+ catch (OperationCanceledException)
+ {
+ await DisplayAlert("Logout timed out", "The logout process was aborted.", "OK");
+ }
+
+ catch
+ {
+ await DisplayAlert("Logout failed", "An error occurred while trying to log the user out.", "OK");
+ }
+ }
+
+ finally
+ {
+ // Re-enable the buttons to allow starting a new operation.
+ LocalLogin.IsEnabled = true;
+ LocalLoginWithGitHub.IsEnabled = true;
+ LocalLogout.IsEnabled = true;
+ TwitterLogin.IsEnabled = true;
+ }
+ }
+}
+#endif
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/MauiHostApplicationLifetime.cs b/sandbox/OpenIddict.Sandbox.Maui.Client/MauiHostApplicationLifetime.cs
new file mode 100644
index 00000000..e3d25bdb
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/MauiHostApplicationLifetime.cs
@@ -0,0 +1,22 @@
+#if IOS || WINDOWS
+using Microsoft.Extensions.Hosting;
+
+namespace OpenIddict.Sandbox.Maui.Client;
+
+public class MauiHostApplicationLifetime : IHostApplicationLifetime
+{
+ private readonly CancellationTokenSource _source = new();
+
+ public CancellationToken ApplicationStarted => new(canceled: true);
+
+ public CancellationToken ApplicationStopping => _source.Token;
+
+ public CancellationToken ApplicationStopped => _source.Token;
+
+ public void StopApplication()
+ {
+ _source.Cancel(throwOnFirstException: false);
+ Environment.Exit(0);
+ }
+}
+#endif
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/MauiHostedServiceAdapter.cs b/sandbox/OpenIddict.Sandbox.Maui.Client/MauiHostedServiceAdapter.cs
new file mode 100644
index 00000000..8bc1a73a
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/MauiHostedServiceAdapter.cs
@@ -0,0 +1,16 @@
+#if IOS || WINDOWS
+using Microsoft.Extensions.Hosting;
+
+namespace OpenIddict.Sandbox.Maui.Client;
+
+public class MauiHostedServiceAdapter : IMauiInitializeService
+{
+ private readonly IHostedService _service;
+
+ public MauiHostedServiceAdapter(IHostedService service)
+ => _service = service ?? throw new ArgumentNullException(nameof(service));
+
+ public void Initialize(IServiceProvider services)
+ => Task.Run(() => _service.StartAsync(CancellationToken.None)).GetAwaiter().GetResult();
+}
+#endif
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/MauiProgram.cs b/sandbox/OpenIddict.Sandbox.Maui.Client/MauiProgram.cs
new file mode 100644
index 00000000..17efd7f3
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/MauiProgram.cs
@@ -0,0 +1,131 @@
+#if IOS || WINDOWS
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Hosting.Internal;
+using Microsoft.Extensions.Logging;
+using OpenIddict.Client;
+using OpenIddict.Client.SystemIntegration;
+using static OpenIddict.Abstractions.OpenIddictConstants;
+
+namespace OpenIddict.Sandbox.Maui.Client;
+
+public static class MauiProgram
+{
+ public static MauiApp CreateMauiApp()
+ {
+ var builder = MauiApp.CreateBuilder();
+
+ builder.Logging.AddDebug();
+
+ builder.Services.AddDbContext(options =>
+ {
+ options.UseSqlite($"Filename={Path.Combine(Path.GetTempPath(), "openiddict-sandbox-maui-client.sqlite3")}");
+ options.UseOpenIddict();
+ });
+
+ builder.Services.AddOpenIddict()
+
+ // Register the OpenIddict core components.
+ .AddCore(options =>
+ {
+ // Configure OpenIddict to use the Entity Framework Core stores and models.
+ // Note: call ReplaceDefaultEntities() to replace the default OpenIddict entities.
+ options.UseEntityFrameworkCore()
+ .UseDbContext();
+ })
+
+ // Register the OpenIddict client components.
+ .AddClient(options =>
+ {
+ // Note: this sample uses the authorization code and refresh token
+ // flows, but you can enable the other flows if necessary.
+ options.AllowAuthorizationCodeFlow()
+ .AllowRefreshTokenFlow();
+
+ // Register the signing and encryption credentials used to protect
+ // sensitive data like the state tokens produced by OpenIddict.
+ options.AddDevelopmentEncryptionCertificate()
+ .AddDevelopmentSigningCertificate();
+
+ // Register the operating system integration.
+ options.UseSystemIntegration();
+
+ // Register the System.Net.Http integration and use the identity of the current
+ // assembly as a more specific user agent, which can be useful when dealing with
+ // providers that use the user agent as a way to throttle requests (e.g Reddit).
+ options.UseSystemNetHttp()
+ .SetProductInformation(typeof(MauiProgram).Assembly);
+
+ // Add a client registration matching the client application definition in the server project.
+ options.AddRegistration(new OpenIddictClientRegistration
+ {
+ Issuer = new Uri("https://localhost:44395/", UriKind.Absolute),
+ ProviderName = "Local",
+
+ ClientId = "maui",
+
+ // This sample uses protocol activations with a custom URI scheme to handle callbacks.
+ //
+ // For more information on how to construct private-use URI schemes,
+ // read https://www.rfc-editor.org/rfc/rfc8252#section-7.1 and
+ // https://www.rfc-editor.org/rfc/rfc7595#section-3.8.
+ PostLogoutRedirectUri = new Uri("com.openiddict.sandbox.maui.client:/callback/logout/local", UriKind.Absolute),
+ RedirectUri = new Uri("com.openiddict.sandbox.maui.client:/callback/login/local", UriKind.Absolute),
+
+ Scopes = { Scopes.Email, Scopes.Profile, Scopes.OfflineAccess, "demo_api" }
+ });
+
+ // Register the Web providers integrations.
+ //
+ // Note: to mitigate mix-up attacks, it's recommended to use a unique redirection endpoint
+ // address per provider, unless all the registered providers support returning an "iss"
+ // parameter containing their URL as part of authorization responses. For more information,
+ // see https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-4.4.
+ options.UseWebProviders()
+ .AddTwitter(options =>
+ {
+ options.SetClientId("bXgwc0U3N3A3YWNuaWVsdlRmRWE6MTpjaQ")
+ // Note: Twitter doesn't support the recommended ":/" syntax and requires using "://".
+ .SetRedirectUri("com.openiddict.sandbox.maui.client://callback/login/twitter");
+ });
+ });
+
+ builder.UseMauiApp()
+ .ConfigureFonts(options =>
+ {
+ options.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
+ options.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
+ });
+
+ // Note: MAUI is not built on top of the .NET Generic Host and doesn't register any of
+ // the services typically found in applications using the .NET Generic Host. Since these
+ // services are required by the OpenIddict client system integration to handle callbacks
+ // and redirect protocol activations to the correct instance, custom implementations are
+ // registered here. For more information, see https://github.com/dotnet/maui/issues/2244.
+
+ builder.Services.AddSingleton(new HostingEnvironment
+ {
+ ApplicationName = typeof(MauiProgram).Assembly.GetName().Name!
+ });
+
+ builder.Services.AddSingleton();
+
+ builder.Services.AddSingleton(static provider => new MauiHostedServiceAdapter(
+ ActivatorUtilities.CreateInstance(provider)));
+
+ builder.Services.AddSingleton(static provider => new MauiHostedServiceAdapter(
+ ActivatorUtilities.CreateInstance(provider)));
+
+ builder.Services.AddSingleton(static provider => new MauiHostedServiceAdapter(
+ ActivatorUtilities.CreateInstance(provider)));
+
+ // Note: pages must be registered in the container to be able to use constructor injection.
+ builder.Services.AddSingleton();
+
+ // Register the initialization service responsible for creating the SQLite database.
+ builder.Services.AddScoped();
+
+ return builder.Build();
+ }
+}
+#endif
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/OpenIddict.Sandbox.Maui.Client.csproj b/sandbox/OpenIddict.Sandbox.Maui.Client/OpenIddict.Sandbox.Maui.Client.csproj
new file mode 100644
index 00000000..9fbacebc
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/OpenIddict.Sandbox.Maui.Client.csproj
@@ -0,0 +1,47 @@
+
+
+
+ Exe
+ net8.0-windows10.0.19041
+ $(TargetFrameworks);net8.0-ios17.2
+ net8.0
+ true
+ true
+
+
+
+ OpenIddict.Sandbox.Maui.Client
+ com.openiddict.sandbox.maui.client
+ $(Version)
+ $(Version)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/Windows/App.xaml b/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/Windows/App.xaml
new file mode 100644
index 00000000..d269e13b
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/Windows/App.xaml
@@ -0,0 +1,8 @@
+
+
+
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/Windows/App.xaml.cs b/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/Windows/App.xaml.cs
new file mode 100644
index 00000000..2d6a2ef7
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/Windows/App.xaml.cs
@@ -0,0 +1,10 @@
+#if WINDOWS
+namespace OpenIddict.Sandbox.Maui.Client.WinUI;
+
+public partial class App : MauiWinUIApplication
+{
+ public App() => InitializeComponent();
+
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+}
+#endif
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/Windows/Package.appxmanifest b/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/Windows/Package.appxmanifest
new file mode 100644
index 00000000..58165cee
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/Windows/Package.appxmanifest
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+ $placeholder$
+ User Name
+ $placeholder$.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OpenIddict MAUI client
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/Windows/app.manifest b/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/Windows/app.manifest
new file mode 100644
index 00000000..bdd50334
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/Windows/app.manifest
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+ true/PM
+ PerMonitorV2, PerMonitor
+
+
+
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/iOS/AppDelegate.cs b/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/iOS/AppDelegate.cs
new file mode 100644
index 00000000..35c0a775
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/iOS/AppDelegate.cs
@@ -0,0 +1,11 @@
+#if IOS
+using Foundation;
+
+namespace OpenIddict.Sandbox.Maui.Client;
+
+[Register("AppDelegate")]
+public class AppDelegate : MauiUIApplicationDelegate
+{
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+}
+#endif
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/iOS/Info.plist b/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/iOS/Info.plist
new file mode 100644
index 00000000..f6cff2d0
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/iOS/Info.plist
@@ -0,0 +1,45 @@
+
+
+
+
+ LSRequiresIPhoneOS
+
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ XSAppIconAssets
+ Assets.xcassets/appicon.appiconset
+ CFBundleURLTypes
+
+
+ CFBundleURLName
+ Type d'URL 1
+ CFBundleURLSchemes
+
+ com.openiddict.sandbox.maui.client
+
+ CFBundleTypeRole
+ Editor
+
+
+
+
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/iOS/Program.cs b/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/iOS/Program.cs
new file mode 100644
index 00000000..25b9ce72
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Platforms/iOS/Program.cs
@@ -0,0 +1,11 @@
+#if IOS
+using ObjCRuntime;
+using UIKit;
+
+namespace OpenIddict.Sandbox.Maui.Client;
+
+public static class Program
+{
+ public static void Main(string[] args) => UIApplication.Main(args, null, typeof(AppDelegate));
+}
+#endif
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Program.cs b/sandbox/OpenIddict.Sandbox.Maui.Client/Program.cs
new file mode 100644
index 00000000..415e6c91
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Program.cs
@@ -0,0 +1,3 @@
+#if !IOS && !WINDOWS
+Console.Error.WriteLine("This sample is only supported on iOS and Windows.");
+#endif
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Properties/launchSettings.json b/sandbox/OpenIddict.Sandbox.Maui.Client/Properties/launchSettings.json
new file mode 100644
index 00000000..edf8aadc
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "Windows Machine": {
+ "commandName": "MsixPackage",
+ "nativeDebugging": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/AppIcon/appicon.svg b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/AppIcon/appicon.svg
new file mode 100644
index 00000000..9d63b651
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/AppIcon/appicon.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/AppIcon/appiconfg.svg b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/AppIcon/appiconfg.svg
new file mode 100644
index 00000000..21dfb25f
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/AppIcon/appiconfg.svg
@@ -0,0 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Fonts/OpenSans-Regular.ttf b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Fonts/OpenSans-Regular.ttf
new file mode 100644
index 00000000..534d0094
Binary files /dev/null and b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Fonts/OpenSans-Regular.ttf differ
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Fonts/OpenSans-Semibold.ttf b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Fonts/OpenSans-Semibold.ttf
new file mode 100644
index 00000000..f3331530
Binary files /dev/null and b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Fonts/OpenSans-Semibold.ttf differ
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Images/dotnet_bot.svg b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Images/dotnet_bot.svg
new file mode 100644
index 00000000..abfaff26
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Images/dotnet_bot.svg
@@ -0,0 +1,93 @@
+
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Raw/AboutAssets.txt b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Raw/AboutAssets.txt
new file mode 100644
index 00000000..15d62448
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Raw/AboutAssets.txt
@@ -0,0 +1,15 @@
+Any raw assets you want to be deployed with your application can be placed in
+this directory (and child directories). Deployment of the asset to your application
+is automatically handled by the following `MauiAsset` Build Action within your `.csproj`.
+
+
+
+These files will be deployed with you package and will be accessible using Essentials:
+
+ async Task LoadMauiAsset()
+ {
+ using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt");
+ using var reader = new StreamReader(stream);
+
+ var contents = reader.ReadToEnd();
+ }
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Splash/splash.svg b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Splash/splash.svg
new file mode 100644
index 00000000..21dfb25f
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Splash/splash.svg
@@ -0,0 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Styles/Colors.xaml b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Styles/Colors.xaml
new file mode 100644
index 00000000..245758ba
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Styles/Colors.xaml
@@ -0,0 +1,44 @@
+
+
+
+
+ #512BD4
+ #DFD8F7
+ #2B0B98
+ White
+ Black
+ #E1E1E1
+ #C8C8C8
+ #ACACAC
+ #919191
+ #6E6E6E
+ #404040
+ #212121
+ #141414
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #F7B548
+ #FFD590
+ #FFE5B9
+ #28C2D1
+ #7BDDEF
+ #C3F2F4
+ #3E8EED
+ #72ACF1
+ #A7CBF6
+
+
\ No newline at end of file
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Styles/Styles.xaml b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Styles/Styles.xaml
new file mode 100644
index 00000000..1ec9d55f
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Resources/Styles/Styles.xaml
@@ -0,0 +1,384 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sandbox/OpenIddict.Sandbox.Maui.Client/Worker.cs b/sandbox/OpenIddict.Sandbox.Maui.Client/Worker.cs
new file mode 100644
index 00000000..6cac5262
--- /dev/null
+++ b/sandbox/OpenIddict.Sandbox.Maui.Client/Worker.cs
@@ -0,0 +1,14 @@
+#if IOS || WINDOWS
+using Microsoft.EntityFrameworkCore;
+
+namespace OpenIddict.Sandbox.Maui.Client;
+
+public class Worker : IMauiInitializeScopedService
+{
+ public void Initialize(IServiceProvider services)
+ {
+ var context = services.GetRequiredService();
+ context.Database.EnsureCreated();
+ }
+}
+#endif
diff --git a/sandbox/OpenIddict.Sandbox.WinForms.Client/OpenIddict.Sandbox.WinForms.Client.csproj b/sandbox/OpenIddict.Sandbox.WinForms.Client/OpenIddict.Sandbox.WinForms.Client.csproj
index 5bedbe98..44719f06 100644
--- a/sandbox/OpenIddict.Sandbox.WinForms.Client/OpenIddict.Sandbox.WinForms.Client.csproj
+++ b/sandbox/OpenIddict.Sandbox.WinForms.Client/OpenIddict.Sandbox.WinForms.Client.csproj
@@ -2,11 +2,9 @@
WinExe
- net48;net8.0-windows7.0
- true
+ net48
+ $(TargetFrameworks);net8.0-windows7.0
true
- false
- false
diff --git a/sandbox/OpenIddict.Sandbox.Wpf.Client/OpenIddict.Sandbox.Wpf.Client.csproj b/sandbox/OpenIddict.Sandbox.Wpf.Client/OpenIddict.Sandbox.Wpf.Client.csproj
index 0b06bc73..6eed25c1 100644
--- a/sandbox/OpenIddict.Sandbox.Wpf.Client/OpenIddict.Sandbox.Wpf.Client.csproj
+++ b/sandbox/OpenIddict.Sandbox.Wpf.Client/OpenIddict.Sandbox.Wpf.Client.csproj
@@ -2,11 +2,9 @@
WinExe
- net48;net8.0-windows10.0.17763
- true
+ net48
+ $(TargetFrameworks);net8.0-windows10.0.17763
true
- false
- false
false
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddict.Client.SystemIntegration.csproj b/src/OpenIddict.Client.SystemIntegration/OpenIddict.Client.SystemIntegration.csproj
index 3c1b3664..eef7b032 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddict.Client.SystemIntegration.csproj
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddict.Client.SystemIntegration.csproj
@@ -10,7 +10,6 @@
$(UniversalWindowsPlatformTargetFrameworks)
true
- true
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs
index 625a90b4..e09693d5 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs
@@ -136,6 +136,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
}
});
+#if SUPPORTS_PRESENTATION_CONTEXT_PROVIDER
// On iOS 13.0 and higher, a presentation context provider returning the UI window to
// which the Safari web view will be attached MUST be provided (otherwise, a code 2
// error is returned by ASWebAuthenticationSession). To avoid that, a default provider
@@ -148,7 +149,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0447)));
#pragma warning restore CA1416
}
-
+#endif
using var registration = context.CancellationToken.Register(
static state => ((ASWebAuthenticationSession) state!).Cancel(), session);
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs
index 0c91d750..0adb3a16 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs
@@ -136,6 +136,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
}
});
+#if SUPPORTS_PRESENTATION_CONTEXT_PROVIDER
// On iOS 13.0 and higher, a presentation context provider returning the UI window to
// which the Safari web view will be attached MUST be provided (otherwise, a code 2
// error is returned by ASWebAuthenticationSession). To avoid that, a default provider
@@ -148,7 +149,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0447)));
#pragma warning restore CA1416
}
-
+#endif
using var registration = context.CancellationToken.Register(
static state => ((ASWebAuthenticationSession) state!).Cancel(), session);
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs
index b9c3634b..a3f0215c 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs
@@ -248,7 +248,7 @@ public static class OpenIddictClientSystemIntegrationHelpers
out uint ReturnLength);
}
-#if SUPPORTS_UIKIT
+#if SUPPORTS_PRESENTATION_CONTEXT_PROVIDER
///
/// Gets a reference to the current .
///
diff --git a/src/OpenIddict/OpenIddict.csproj b/src/OpenIddict/OpenIddict.csproj
index c8f0c3a1..4d366996 100644
--- a/src/OpenIddict/OpenIddict.csproj
+++ b/src/OpenIddict/OpenIddict.csproj
@@ -12,7 +12,6 @@
false
false
false
- true