IdentityModel.OidcClient
IdentityModel.OidcClient copied to clipboard
Not passing StartUrl to Browser in .net-ios
I have upgraded my Xamarin apps to .net8.0-ios rather than NetMaui. .net8.0-ios is very much supported now and will be in the future. When I upgrade IdentityModel.OidcClient to version 6.0.0, when it makes the call to open the Browser, it no longer passes a StartUrl. The parameter is null. My Browser is implemented as follows.
public class ASWebAuthenticationSessionBrowser : IOSBrowserBase
{
public ASWebAuthenticationSessionOptions SessionOptions { get; }
public ASWebAuthenticationSessionBrowser(ASWebAuthenticationSessionOptions sessionOptions = null)
{
SessionOptions = sessionOptions;
}
/// <inheritdoc/>
protected override Task<BrowserResult> Launch(BrowserOptions options, CancellationToken cancellationToken = default)
{
return Start(options, SessionOptions);
}
internal static Task<BrowserResult> Start(BrowserOptions options, ASWebAuthenticationSessionOptions sessionOptions = null)
{
var tcs = new TaskCompletionSource<BrowserResult>();
ASWebAuthenticationSession asWebAuthenticationSession = null;
asWebAuthenticationSession = new ASWebAuthenticationSession(
new NSUrl(options.StartUrl),
new NSUrl(options.EndUrl).Scheme,
(callbackUrl, error) =>
{
tcs.SetResult(CreateBrowserResult(callbackUrl, error));
asWebAuthenticationSession.Dispose();
});
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
{
// iOS 13 requires the PresentationContextProvider set
asWebAuthenticationSession.PresentationContextProvider = new PresentationContextProviderToSharedKeyWindow();
// PrefersEphemeralWebBrowserSession is only available on iOS 13 and up.
asWebAuthenticationSession.PrefersEphemeralWebBrowserSession = sessionOptions != null ? sessionOptions.PrefersEphemeralWebBrowserSession : false;
}
asWebAuthenticationSession.Start();
return tcs.Task;
}
class PresentationContextProviderToSharedKeyWindow : NSObject, IASWebAuthenticationPresentationContextProviding
{
public UIWindow GetPresentationAnchor(ASWebAuthenticationSession session)
{
return UIApplication.SharedApplication.KeyWindow;
}
}
private static BrowserResult CreateBrowserResult(NSUrl callbackUrl, NSError error)
{
if (error == null)
return Success(callbackUrl.AbsoluteString);
if (error.Code == (long)ASWebAuthenticationSessionErrorCode.CanceledLogin)
return Canceled();
return UnknownError(error.ToString());
}
}
public abstract class IOSBrowserBase : IBrowser
{
public Task<BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(options.StartUrl))
throw new ArgumentException("Missing StartUrl", nameof(options));
if (string.IsNullOrWhiteSpace(options.EndUrl))
throw new ArgumentException("Missing EndUrl", nameof(options));
return Launch(options, cancellationToken);
}
protected abstract Task<BrowserResult> Launch(BrowserOptions options, CancellationToken cancellationToken = default);
internal static BrowserResult Canceled()
{
return new BrowserResult
{
ResultType = BrowserResultType.UserCancel
};
}
internal static BrowserResult UnknownError(string error)
{
return new BrowserResult
{
ResultType = BrowserResultType.UnknownError,
Error = error
};
}
internal static BrowserResult Success(string response)
{
return new BrowserResult
{
Response = response,
ResultType = BrowserResultType.Success
};
}
}
I Use the following code to invoke a login:
_options = new OidcClientOptions
{
Authority = vm.Config["Settings:Authority"],
ClientId = vm.Config["Settings:ClientId"],
Scope = vm.Config["Settings:Scope"],
RedirectUri = vm.Config["Settings:RedirectUri"],
PostLogoutRedirectUri = vm.Config["Settings:RedirectUri"],
Browser = new ASWebAuthenticationSessionBrowser(new ASWebAuthenticationSessionOptions
{
PrefersEphemeralWebBrowserSession = true
})
};
var oidcClient = new OidcClient(_options);
try
{
var result = await oidcClient.LoginAsync();
//Use the following in place of the above if you want to force a login
//var parm = new Parameters
//{
// { "prompt", "login" }
//};
//var result = await oidcClient.LoginAsync(new LoginRequest { FrontChannelExtraParameters = parm });
if (!result.IsError)
{
vm.Tokens.AccessToken = result.AccessToken;
vm.Tokens.IdentityToken = result.IdentityToken;
vm.Tokens.RefreshToken = result.RefreshToken;
vm.Tokens.AccessTokenExpiration = result.AccessTokenExpiration.DateTime.ToUniversalTime();
vm.Tokens.Error = result.Error;
//vm.Tokens.User = result.User;
vm.Logger.LogInformation("{0} logged in!", result.User.Identity.Name);
}
}
catch (Exception ex)
{
var s = ex.ToString();
}
It works fine with version 5.2.1 but breaks in version 6.0.0. Is there anything I can do other than rewrite my app in NetMaui? I do have some paid time left with Duende if I need to use that to resolve this.
Thanks, Jim