| File: WebAuthenticator\WebAuthenticator.shared.cs | Web Access |
| Project: src\src\Essentials\src\Essentials.csproj (Microsoft.Maui.Essentials) |
#nullable enable using System; using System.Collections.Generic; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.Maui.ApplicationModel; namespace Microsoft.Maui.Authentication { /// <summary> /// A web navigation API intended to be used for authentication with external web services such as OAuth. /// </summary> public interface IWebAuthenticator { /// <summary> /// Begin an authentication flow by navigating to the specified URL and waiting for a callback/redirect to the callback URL scheme. /// </summary> /// <param name="webAuthenticatorOptions">A <see cref="WebAuthenticatorOptions"/> instance containing additional configuration for this authentication call.</param> /// <returns>A <see cref="WebAuthenticatorResult"/> object with the results of this operation.</returns> /// <exception cref="TaskCanceledException">Thrown when the user canceled the authentication flow.</exception> /// <exception cref="PlatformNotSupportedException">Windows: Thrown when called on Windows.</exception> /// <exception cref="FeatureNotSupportedException">iOS/macOS: Thrown when iOS version is less than 13 is used or macOS less than 13.1 is used.</exception> /// <exception cref="InvalidOperationException"> /// <para>Android: Thrown when the no IntentFilter has been created for the callback URL.</para> /// </exception> Task<WebAuthenticatorResult> AuthenticateAsync(WebAuthenticatorOptions webAuthenticatorOptions); } /// <summary> /// Provides abstractions for the platform web authenticator callbacks triggered when using <see cref="WebAuthenticator"/>. /// </summary> public interface IPlatformWebAuthenticatorCallback { #if IOS || MACCATALYST || MACOS /// <summary> /// Opens the specified URI to start the authentication flow. /// </summary> /// <param name="uri">The URI to open that will start the authentication flow.</param> /// <returns><see langword="true"/> when the URI has been opened, otherwise <see langword="false"/>.</returns> bool OpenUrlCallback(Uri uri); #elif ANDROID /// <summary> /// The event that is triggered when an authentication flow calls back into the Android application. /// </summary> /// <param name="intent">An <see cref="Android.Content.Intent"/> object containing additional data about this resume operation.</param> /// <returns><see langword="true"/> when the callback can be processed, otherwise <see langword="false"/>.</returns> bool OnResumeCallback(Android.Content.Intent intent); #endif } /// <summary> /// Provides abstractions used for decoding a URI returned from a authentication request, for use with <see cref="IWebAuthenticator"/>. /// </summary> public interface IWebAuthenticatorResponseDecoder { /// <summary> /// Decodes the given URIs query string into a dictionary. /// </summary> /// <param name="uri">The <see cref="Uri"/> object to decode the query parameters from.</param> /// <returns>A <see cref="IDictionary{TKey, TValue}"/> object where each of the query parameters values of <paramref name="uri"/> are accessible through their respective keys.</returns> IDictionary<string, string>? DecodeResponse(Uri uri); } /// <summary> /// A web navigation API intended to be used for Authentication with external web services such as OAuth. /// </summary> /// <remarks> /// This API helps with navigating to a start URL and waiting for a callback URL to the app. Your app must /// be registered to handle the callback scheme you provide in the call to authenticate. /// </remarks> public static class WebAuthenticator { /// <summary>Begin an authentication flow by navigating to the specified url and waiting for a callback/redirect to the callbackUrl scheme.</summary> /// <param name="url"> Url to navigate to, beginning the authentication flow.</param> /// <param name="callbackUrl"> Expected callback url that the navigation flow will eventually redirect to.</param> /// <returns>Returns a result parsed out from the callback url.</returns> #if !NETSTANDARD [System.Runtime.Versioning.UnsupportedOSPlatform("windows")] #endif public static Task<WebAuthenticatorResult> AuthenticateAsync(Uri url, Uri callbackUrl) => Current.AuthenticateAsync(url, callbackUrl); /// <summary>Begin an authentication flow by navigating to the specified url and waiting for a callback/redirect to the callbackUrl scheme.The start url and callbackUrl are specified in the webAuthenticatorOptions.</summary> /// <param name="webAuthenticatorOptions">Options to configure the authentication request.</param> /// <returns>Returns a result parsed out from the callback url.</returns> #if !NETSTANDARD [System.Runtime.Versioning.UnsupportedOSPlatform("windows")] #endif public static Task<WebAuthenticatorResult> AuthenticateAsync(WebAuthenticatorOptions webAuthenticatorOptions) => Current.AuthenticateAsync(webAuthenticatorOptions); static IWebAuthenticator Current => Authentication.WebAuthenticator.Default; static IWebAuthenticator? defaultImplementation; /// <summary> /// Provides the default implementation for static usage of this API. /// </summary> public static IWebAuthenticator Default => defaultImplementation ??= new WebAuthenticatorImplementation(); internal static void SetDefault(IWebAuthenticator? implementation) => defaultImplementation = implementation; } /// <summary> /// This class contains static extension methods for use with <see cref="WebAuthenticator"/>. /// </summary> public static class WebAuthenticatorExtensions { static IPlatformWebAuthenticatorCallback AsPlatformCallback(this IWebAuthenticator webAuthenticator) { if (webAuthenticator is not IPlatformWebAuthenticatorCallback platform) throw new PlatformNotSupportedException("This implementation of IWebAuthenticator does not implement IPlatformWebAuthenticatorCallback."); return platform; } #if ANDROID internal static bool IsAuthenticatingWithCustomTabs(this IWebAuthenticator webAuthenticator) => (webAuthenticator as WebAuthenticatorImplementation)?.AuthenticatingWithCustomTabs ?? false; #endif /// <summary> /// Begin an authentication flow by navigating to the specified url and waiting for a callback/redirect to the callbackUrl scheme. /// </summary> /// <param name="webAuthenticator">The <see cref="IWebAuthenticator"/> to use for the authentication flow.</param> /// <param name="url"> Url to navigate to, beginning the authentication flow.</param> /// <param name="callbackUrl"> Expected callback url that the navigation flow will eventually redirect to.</param> /// <returns>Returns a result parsed out from the callback url.</returns> public static Task<WebAuthenticatorResult> AuthenticateAsync(this IWebAuthenticator webAuthenticator, Uri url, Uri callbackUrl) => webAuthenticator.AuthenticateAsync(new WebAuthenticatorOptions { Url = url, CallbackUrl = callbackUrl }); #if IOS || MACCATALYST || MACOS /// <inheritdoc cref="IPlatformWebAuthenticatorCallback.OpenUrlCallback(Uri)"/> public static bool OpenUrl(this IWebAuthenticator webAuthenticator, Uri uri) => webAuthenticator.AsPlatformCallback().OpenUrlCallback(uri); /// <inheritdoc cref="ApplicationModel.Platform.OpenUrl(UIKit.UIApplication, Foundation.NSUrl, Foundation.NSDictionary)"/> public static bool OpenUrl(this IWebAuthenticator webAuthenticator, UIKit.UIApplication app, Foundation.NSUrl url, Foundation.NSDictionary options) { if(url?.AbsoluteString != null) { return webAuthenticator.OpenUrl(new Uri(url.AbsoluteString)); } return false; } /// <inheritdoc cref="ApplicationModel.Platform.ContinueUserActivity(UIKit.UIApplication, Foundation.NSUserActivity, UIKit.UIApplicationRestorationHandler)"/> public static bool ContinueUserActivity(this IWebAuthenticator webAuthenticator, UIKit.UIApplication application, Foundation.NSUserActivity userActivity, UIKit.UIApplicationRestorationHandler completionHandler) { var uri = userActivity?.WebPageUrl?.AbsoluteString; if (string.IsNullOrEmpty(uri)) return false; return webAuthenticator.OpenUrl(new Uri(uri)); } #elif ANDROID /// <inheritdoc cref="IPlatformWebAuthenticatorCallback.OnResumeCallback(Android.Content.Intent)"/> public static bool OnResume(this IWebAuthenticator webAuthenticator, Android.Content.Intent intent) => webAuthenticator.AsPlatformCallback().OnResumeCallback(intent); #endif } /// <summary> /// Represents additional options for <see cref="WebAuthenticator"/>. /// </summary> public class WebAuthenticatorOptions { /// <summary> /// Gets or sets the URL that will start the authentication flow. /// </summary> public Uri? Url { get; set; } /// <summary> /// Gets or sets the callback URL that should be called when authentication completes. /// </summary> public Uri? CallbackUrl { get; set; } /// <summary> /// Gets or sets whether the browser used for the authentication flow is short-lived. /// This means it will not share session nor cookies with the regular browser on this device if set the <see langword="true"/>. /// </summary> /// <remarks>This setting only has effect on iOS.</remarks> public bool PrefersEphemeralWebBrowserSession { get; set; } /// <summary> /// Gets or sets the decoder implementation used to decode the incoming authentication result URI. /// </summary> public IWebAuthenticatorResponseDecoder? ResponseDecoder { get; set; } } }