File: WebAuthenticator\AppleSignInAuthenticator.ios.cs
Web Access
Project: src\src\Essentials\src\Essentials.csproj (Microsoft.Maui.Essentials)
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AuthenticationServices;
using Foundation;
using Microsoft.Maui.ApplicationModel;
using UIKit;
 
namespace Microsoft.Maui.Authentication
{
	partial class AppleSignInAuthenticatorImplementation : IAppleSignInAuthenticator
	{
		AuthManager authManager;
 
		public async Task<WebAuthenticatorResult> AuthenticateAsync(AppleSignInAuthenticator.Options options)
		{
			if (OperatingSystem.IsIOS() && !OperatingSystem.IsIOSVersionAtLeast(13))
				throw new FeatureNotSupportedException();
 
			if (OperatingSystem.IsMacCatalyst() && !OperatingSystem.IsMacCatalystVersionAtLeast(13, 1))
				throw new FeatureNotSupportedException();
 
			var provider = new ASAuthorizationAppleIdProvider();
			var req = provider.CreateRequest();
 
			authManager = new AuthManager(WindowStateManager.Default.GetCurrentUIWindow(true));
 
			var scopes = new List<ASAuthorizationScope>();
 
			if (options.IncludeFullNameScope)
				scopes.Add(ASAuthorizationScope.FullName);
			if (options.IncludeEmailScope)
				scopes.Add(ASAuthorizationScope.Email);
 
			req.RequestedScopes = scopes.ToArray();
			var controller = new ASAuthorizationController(new[] { req });
 
			controller.Delegate = authManager;
			controller.PresentationContextProvider = authManager;
 
			controller.PerformRequests();
 
			var creds = await authManager.GetCredentialsAsync();
 
			if (creds == null)
				return null;
 
			var idToken = new NSString(creds.IdentityToken, NSStringEncoding.UTF8).ToString();
			var authCode = new NSString(creds.AuthorizationCode, NSStringEncoding.UTF8).ToString();
			var name = NSPersonNameComponentsFormatter.GetLocalizedString(creds.FullName, NSPersonNameComponentsFormatterStyle.Default, 0);
 
			var appleAccount = new WebAuthenticatorResult();
			appleAccount.Properties.Add("id_token", idToken);
			appleAccount.Properties.Add("authorization_code", authCode);
			appleAccount.Properties.Add("state", creds.State);
			appleAccount.Properties.Add("email", creds.Email);
			appleAccount.Properties.Add("user_id", creds.User);
			appleAccount.Properties.Add("name", name);
			appleAccount.Properties.Add("realuserstatus", creds.RealUserStatus.ToString());
 
			return appleAccount;
		}
	}
 
	[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
	[System.Runtime.Versioning.SupportedOSPlatform("maccatalyst13.1")]
	class AuthManager : NSObject, IASAuthorizationControllerDelegate, IASAuthorizationControllerPresentationContextProviding
	{
		public Task<ASAuthorizationAppleIdCredential> GetCredentialsAsync()
			=> tcsCredential?.Task;
 
		TaskCompletionSource<ASAuthorizationAppleIdCredential> tcsCredential;
 
		UIWindow presentingAnchor;
 
		public AuthManager(UIWindow presentingWindow)
		{
			tcsCredential = new TaskCompletionSource<ASAuthorizationAppleIdCredential>();
			presentingAnchor = presentingWindow;
		}
 
		public UIWindow GetPresentationAnchor(ASAuthorizationController controller)
			=> presentingAnchor;
 
		[Export("authorizationController:didCompleteWithAuthorization:")]
		public void DidComplete(ASAuthorizationController controller, ASAuthorization authorization)
		{
			var creds = authorization.GetCredential<ASAuthorizationAppleIdCredential>();
			tcsCredential?.TrySetResult(creds);
		}
 
		[Export("authorizationController:didCompleteWithError:")]
		public void DidComplete(ASAuthorizationController controller, NSError error)
			=> tcsCredential?.TrySetException(new Exception(error.LocalizedDescription));
	}
}