PostIt.Android: drive the PKCE flow through Chrome Custom Tabs
The earlier commit removed the client_secret and wired
MainActivity.OnNewIntent to AndroidOidcCallbackSink, but
IdentityModel.OidcClient.LoginAsync still had no IBrowser to drive
the user-agent half of the flow. Without it, the desktop / browser
projects continue to fail at login with 'No browser is available'.
Android now plugs in Chrome Custom Tabs:
* PostIt.Android/Services/AndroidSystemBrowser.cs implements
IBrowser.InvokeAsync using CustomTabsIntent.LaunchUrl and waits
for MainActivity.AndroidOidcCallbackSink to deliver the deep-link
Intent (android://postit-signin?code=...&state=...).
* PostIt/Services/Platform.cs is a tiny static indirection the
shared library uses to ask the running platform for an
IBrowser and the appropriate default RedirectUri, without
referencing any UI framework from the shared assembly.
* LoginPageViewModel reads Platform.DefaultRedirectUri and
Platform.CreateBrowser().Invoke() before calling LoginAsync.
* PostIt.Android/PlatformBootstrap.cs wires the Android side at
startup, and MainActivity.OnCreate calls EnsureInitialized().
* Xamarin.AndroidX.Browser 1.8.0 added to the central package
versions so CustomTabsIntent resolves.
This commit is contained in:
parent
512a0ef06f
commit
c172d1cf9e
7 changed files with 177 additions and 6 deletions
28
src/PostIt/PostIt/Services/Platform.cs
Normal file
28
src/PostIt/PostIt/Services/Platform.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using IdentityModel.OidcClient.Browser;
|
||||
|
||||
namespace PostIt.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Per-platform access to native integration points used by the OIDC
|
||||
/// Authorization Code + PKCE flow. The shared <c>PostIt</c> library does
|
||||
/// not reference any UI framework; platform projects (PostIt.Android,
|
||||
/// PostIt.Desktop, PostIt.Browser) populate this class once at startup so
|
||||
/// the shared <c>LoginPageViewModel</c> can drive a native browser without
|
||||
/// taking a hard dependency on any specific UI toolkit.
|
||||
/// </summary>
|
||||
public static class Platform
|
||||
{
|
||||
/// <summary>
|
||||
/// Default redirect URI for the running platform. The desktop loopback
|
||||
/// default is set here; platform projects override this property at
|
||||
/// startup (e.g. PostIt.Android sets it to <c>android://postit-signin</c>).
|
||||
/// </summary>
|
||||
public static string DefaultRedirectUri { get; set; } = "http://127.0.0.1:7890/";
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a fresh <see cref="IBrowser"/> for the running platform.
|
||||
/// May return <c>null</c> if no browser is wired up; in that case
|
||||
/// <c>LoginAsync</c> will surface a clear error.
|
||||
/// </summary>
|
||||
public static System.Func<IBrowser?>? CreateBrowser { get; set; }
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
using CommunityToolkit.Mvvm.Input;
|
||||
using IdentityModel.OidcClient;
|
||||
using PostIt.Services;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -21,7 +22,7 @@ public partial class LoginPageViewModel : ViewModelBase
|
|||
|
||||
private string _StatusMessage;
|
||||
public string StatusMessage { get => _StatusMessage; private set => this.SetProperty(ref _StatusMessage, value); }
|
||||
|
||||
|
||||
private bool _IsBusy;
|
||||
public bool IsBusy { get=> _IsBusy; private set=> this.SetProperty(ref _IsBusy, value); }
|
||||
|
||||
|
|
@ -37,10 +38,23 @@ public partial class LoginPageViewModel : ViewModelBase
|
|||
try
|
||||
{
|
||||
Settings.Load().Wait();
|
||||
|
||||
var client = new OidcClient(Settings.GetOidcClientOptions());
|
||||
|
||||
// The platform project picks the right redirect URI and browser
|
||||
// implementation; we don't reference any UI toolkit from here.
|
||||
Settings.RedirectUri = string.IsNullOrWhiteSpace(Settings.RedirectUri)
|
||||
? Platform.DefaultRedirectUri
|
||||
: Settings.RedirectUri;
|
||||
|
||||
var browser = Platform.CreateBrowser?.Invoke();
|
||||
if (browser is null)
|
||||
{
|
||||
StatusMessage = "No browser is available on this platform.";
|
||||
return;
|
||||
}
|
||||
|
||||
var client = new OidcClient(Settings.GetOidcClientOptions(browser));
|
||||
var loginResult = await client.LoginAsync(new LoginRequest());
|
||||
|
||||
|
||||
if (loginResult.IsError)
|
||||
{
|
||||
StatusMessage = loginResult.Error;
|
||||
|
|
@ -51,12 +65,12 @@ public partial class LoginPageViewModel : ViewModelBase
|
|||
|
||||
this.IsBusy = false;
|
||||
AccessToken = loginResult.AccessToken;
|
||||
/* TODO save or not user log and password
|
||||
/* TODO save or not user log and password
|
||||
await Task.Run(() =>
|
||||
{
|
||||
Settings.Save().Wait();
|
||||
});*/
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue