From 5f94094a655ab9c3865b6d796c9b53984dbe8f60 Mon Sep 17 00:00:00 2001 From: ImmutableJeffrey Date: Fri, 8 Aug 2025 18:40:07 +1000 Subject: [PATCH] chore: update direct login support to use direct login options (#3896) --- .../Scripts/Passport/Login/LoginScript.cs | 35 ++++++------- .../Private/Model/DirectLoginMethod.cs | 4 +- .../Private/Model/DirectLoginOptions.cs | 51 +++++++++++++++++++ .../Private/Model/DirectLoginOptions.cs.meta | 11 ++++ .../Model/Request/GetPKCEAuthUrlRequest.cs | 12 ++--- .../Runtime/Scripts/Private/PassportImpl.cs | 30 ++++++++--- .../Runtime/Scripts/Public/Passport.cs | 12 ++--- 7 files changed, 117 insertions(+), 38 deletions(-) create mode 100644 src/Packages/Passport/Runtime/Scripts/Private/Model/DirectLoginOptions.cs create mode 100644 src/Packages/Passport/Runtime/Scripts/Private/Model/DirectLoginOptions.cs.meta diff --git a/sample/Assets/Scripts/Passport/Login/LoginScript.cs b/sample/Assets/Scripts/Passport/Login/LoginScript.cs index 1fe324fb..b0f8a3ba 100644 --- a/sample/Assets/Scripts/Passport/Login/LoginScript.cs +++ b/sample/Assets/Scripts/Passport/Login/LoginScript.cs @@ -27,11 +27,11 @@ void Start() ShowOutput("Passport Instance is null"); } - // Set up button listeners if buttons are assigned - if (DefaultLoginButton != null) DefaultLoginButton.onClick.AddListener(() => Login(DirectLoginMethod.None)); - if (GoogleLoginButton != null) GoogleLoginButton.onClick.AddListener(() => Login(DirectLoginMethod.Google)); - if (AppleLoginButton != null) AppleLoginButton.onClick.AddListener(() => Login(DirectLoginMethod.Apple)); - if (FacebookLoginButton != null) FacebookLoginButton.onClick.AddListener(() => Login(DirectLoginMethod.Facebook)); + // Set up button listeners using DirectLoginOptions + if (DefaultLoginButton != null) DefaultLoginButton.onClick.AddListener(() => Login(new DirectLoginOptions())); + if (GoogleLoginButton != null) GoogleLoginButton.onClick.AddListener(() => Login(new DirectLoginOptions(DirectLoginMethod.Google))); + if (AppleLoginButton != null) AppleLoginButton.onClick.AddListener(() => Login(new DirectLoginOptions(DirectLoginMethod.Apple))); + if (FacebookLoginButton != null) FacebookLoginButton.onClick.AddListener(() => Login(new DirectLoginOptions(DirectLoginMethod.Facebook))); } /// @@ -39,39 +39,40 @@ void Start() /// public async void Login() { - await LoginAsync(DirectLoginMethod.None); + await LoginAsync(new DirectLoginOptions()); } /// - /// Logs into Passport using the specified direct login method. + /// Logs into Passport using the specified direct login options. /// - /// The direct login method to use (Google, Apple, Facebook, or None for default) - public async void Login(DirectLoginMethod directLoginMethod) + /// The direct login options + public async void Login(DirectLoginOptions directLoginOptions) { - await LoginAsync(directLoginMethod); + await LoginAsync(directLoginOptions); } /// /// Internal async method that performs the actual login logic. /// - /// The direct login method to use - private async System.Threading.Tasks.Task LoginAsync(DirectLoginMethod directLoginMethod) + /// The direct login options + private async System.Threading.Tasks.Task LoginAsync(DirectLoginOptions directLoginOptions) { try { - string methodName = directLoginMethod == DirectLoginMethod.None ? "default" : directLoginMethod.ToString(); - ShowOutput($"Logging in with {methodName} method..."); + string directLoginMethod = directLoginOptions.directLoginMethod.ToString().ToLower(); - bool success = await Passport.Login(useCachedSession: false, directLoginMethod: directLoginMethod); + ShowOutput($"Logging in with {directLoginMethod} method..."); + + bool success = await Passport.Login(useCachedSession: false, directLoginOptions: directLoginOptions); if (success) { - ShowOutput($"Successfully logged in with {methodName}"); + ShowOutput($"Successfully logged in with {directLoginMethod}"); SceneManager.LoadScene("AuthenticatedScene"); } else { - ShowOutput($"Failed to log in with {methodName}"); + ShowOutput($"Failed to log in with {directLoginMethod}"); } } catch (OperationCanceledException ex) diff --git a/src/Packages/Passport/Runtime/Scripts/Private/Model/DirectLoginMethod.cs b/src/Packages/Passport/Runtime/Scripts/Private/Model/DirectLoginMethod.cs index b844059e..5996371f 100644 --- a/src/Packages/Passport/Runtime/Scripts/Private/Model/DirectLoginMethod.cs +++ b/src/Packages/Passport/Runtime/Scripts/Private/Model/DirectLoginMethod.cs @@ -3,12 +3,12 @@ namespace Immutable.Passport.Model { /// - /// Enum for direct login methods supported by Passport. + /// Enum representing direct login methods for authentication providers. /// [Serializable] public enum DirectLoginMethod { - None, + Email, Google, Apple, Facebook diff --git a/src/Packages/Passport/Runtime/Scripts/Private/Model/DirectLoginOptions.cs b/src/Packages/Passport/Runtime/Scripts/Private/Model/DirectLoginOptions.cs new file mode 100644 index 00000000..fbf157d3 --- /dev/null +++ b/src/Packages/Passport/Runtime/Scripts/Private/Model/DirectLoginOptions.cs @@ -0,0 +1,51 @@ +using System; + +namespace Immutable.Passport.Model +{ + /// + /// Structure representing direct login options for authentication. + /// Can be used for social login (google, apple, facebook) or email login. + /// + [Serializable] + public class DirectLoginOptions + { + /// + /// Authentication method. + /// + public DirectLoginMethod directLoginMethod = DirectLoginMethod.Email; + + /// + /// Email address for email-based authentication (only used when directLoginMethod is Email). + /// + public string email; + + /// + /// Default constructor. + /// + public DirectLoginOptions() + { + directLoginMethod = DirectLoginMethod.Email; + email = null; + } + + /// + /// Constructor with method and email. + /// + /// The direct login method + /// The email address (optional) + public DirectLoginOptions(DirectLoginMethod loginMethod, string emailAddress = null) + { + directLoginMethod = loginMethod; + email = emailAddress; + } + + /// + /// Checks if the email is valid and should be included in requests. + /// + /// True if email is valid for email method + public bool IsEmailValid() + { + return directLoginMethod == DirectLoginMethod.Email && !string.IsNullOrEmpty(email); + } + } +} \ No newline at end of file diff --git a/src/Packages/Passport/Runtime/Scripts/Private/Model/DirectLoginOptions.cs.meta b/src/Packages/Passport/Runtime/Scripts/Private/Model/DirectLoginOptions.cs.meta new file mode 100644 index 00000000..68fb0f8c --- /dev/null +++ b/src/Packages/Passport/Runtime/Scripts/Private/Model/DirectLoginOptions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ed3a815625ef4486db09be9f7dac86d6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Packages/Passport/Runtime/Scripts/Private/Model/Request/GetPKCEAuthUrlRequest.cs b/src/Packages/Passport/Runtime/Scripts/Private/Model/Request/GetPKCEAuthUrlRequest.cs index d2d2643c..418967fa 100644 --- a/src/Packages/Passport/Runtime/Scripts/Private/Model/Request/GetPKCEAuthUrlRequest.cs +++ b/src/Packages/Passport/Runtime/Scripts/Private/Model/Request/GetPKCEAuthUrlRequest.cs @@ -14,19 +14,19 @@ internal class GetPKCEAuthUrlRequest public bool isConnectImx; /// - /// The direct login method to use for authentication. + /// The direct login options for authentication. /// - public string directLoginMethod; + public DirectLoginOptions directLoginOptions; /// - /// Creates a new GetPKCEAuthUrlRequest. + /// Creates a new GetPKCEAuthUrlRequest with DirectLoginOptions. /// /// Whether this is a connect to IMX operation - /// The direct login method to use - public GetPKCEAuthUrlRequest(bool isConnectImx, DirectLoginMethod directLoginMethod) + /// The direct login options to use + public GetPKCEAuthUrlRequest(bool isConnectImx, DirectLoginOptions directLoginOptions) { this.isConnectImx = isConnectImx; - this.directLoginMethod = directLoginMethod == DirectLoginMethod.None ? null : directLoginMethod.ToString().ToLower(); + this.directLoginOptions = directLoginOptions; } } } \ No newline at end of file diff --git a/src/Packages/Passport/Runtime/Scripts/Private/PassportImpl.cs b/src/Packages/Passport/Runtime/Scripts/Private/PassportImpl.cs index 1f0deb8d..b5c91bc2 100644 --- a/src/Packages/Passport/Runtime/Scripts/Private/PassportImpl.cs +++ b/src/Packages/Passport/Runtime/Scripts/Private/PassportImpl.cs @@ -25,7 +25,7 @@ public class PassportImpl private readonly PassportAnalytics _analytics = new(); private bool _pkceLoginOnly; // Used to differentiate between a login and connect - private DirectLoginMethod _directLoginMethod; // Store the direct login method for current operation + private DirectLoginOptions _directLoginOptions; // Store the direct login options for current operation private UniTaskCompletionSource? _pkceCompletionSource; private string _redirectUri; private string _logoutRedirectUri; @@ -98,7 +98,7 @@ public void SetCallTimeout(int ms) _communicationsManager.SetCallTimeout(ms); } - public UniTask Login(bool useCachedSession = false, DirectLoginMethod directLoginMethod = DirectLoginMethod.None) + public UniTask Login(bool useCachedSession = false, DirectLoginOptions directLoginOptions = null) { if (useCachedSession) { @@ -113,7 +113,7 @@ public UniTask Login(bool useCachedSession = false, DirectLoginMethod dire var task = new UniTaskCompletionSource(); _pkceCompletionSource = task; _pkceLoginOnly = true; - _directLoginMethod = directLoginMethod; + _directLoginOptions = directLoginOptions; #if UNITY_STANDALONE_WIN || (UNITY_ANDROID && UNITY_EDITOR_WIN) || (UNITY_IPHONE && UNITY_EDITOR_WIN) WindowsDeepLink.Initialise(_redirectUri, OnDeepLinkActivated); #endif @@ -163,7 +163,7 @@ private async UniTask Relogin() return false; } - public async UniTask ConnectImx(bool useCachedSession = false, DirectLoginMethod directLoginMethod = DirectLoginMethod.None) + public async UniTask ConnectImx(bool useCachedSession = false, DirectLoginOptions directLoginOptions = null) { if (useCachedSession) { @@ -189,7 +189,7 @@ public async UniTask ConnectImx(bool useCachedSession = false, DirectLogin UniTaskCompletionSource task = new UniTaskCompletionSource(); _pkceCompletionSource = task; _pkceLoginOnly = false; - _directLoginMethod = directLoginMethod; + _directLoginOptions = directLoginOptions; #if UNITY_STANDALONE_WIN || (UNITY_ANDROID && UNITY_EDITOR_WIN) || (UNITY_IPHONE && UNITY_EDITOR_WIN) WindowsDeepLink.Initialise(_redirectUri, OnDeepLinkActivated); @@ -275,8 +275,24 @@ private async UniTask LaunchAuthUrl() { try { - var request = new GetPKCEAuthUrlRequest(!_pkceLoginOnly, _directLoginMethod); - var callResponse = await _communicationsManager.Call(PassportFunction.GET_PKCE_AUTH_URL, JsonUtility.ToJson(request)); + // Create the request JSON manually to ensure proper serialization + var requestJson = $"{{\"isConnectImx\":{(!_pkceLoginOnly).ToString().ToLower()}"; + + if (_directLoginOptions != null) + { + requestJson += $",\"directLoginOptions\":{{\"directLoginMethod\":\"{_directLoginOptions.directLoginMethod.ToString().ToLower()}\""; + + if (_directLoginOptions.IsEmailValid()) + { + requestJson += $",\"email\":\"{_directLoginOptions.email}\""; + } + + requestJson += "}"; + } + + requestJson += "}"; + + var callResponse = await _communicationsManager.Call(PassportFunction.GET_PKCE_AUTH_URL, requestJson); var response = callResponse.OptDeserializeObject(); if (response != null && response.success == true && response.result != null) diff --git a/src/Packages/Passport/Runtime/Scripts/Public/Passport.cs b/src/Packages/Passport/Runtime/Scripts/Public/Passport.cs index 60691e4c..83fc4e27 100644 --- a/src/Packages/Passport/Runtime/Scripts/Public/Passport.cs +++ b/src/Packages/Passport/Runtime/Scripts/Public/Passport.cs @@ -292,25 +292,25 @@ public void SetCallTimeout(int ms) /// Logs into Passport using Authorisation Code Flow with Proof Key for Code Exchange (PKCE). /// This opens the user's default browser on desktop or an in-app browser on mobile. /// If true, Passport will attempt to re-authenticate the player using stored credentials. If re-authentication fails, it won't automatically prompt the user to log in again. - /// Optional direct login method to use (google, apple, facebook). If None, the user will see the standard login page. + /// Direct login options for authentication (defaults to email method). /// /// /// Returns true if login is successful, otherwise false. /// - public async UniTask Login(bool useCachedSession = false, DirectLoginMethod directLoginMethod = DirectLoginMethod.None) + public async UniTask Login(bool useCachedSession = false, DirectLoginOptions directLoginOptions = null) { - return await GetPassportImpl().Login(useCachedSession, directLoginMethod); + return await GetPassportImpl().Login(useCachedSession, directLoginOptions); } /// /// Logs the user into Passport using Authorisation Code Flow with Proof Key for Code Exchange (PKCE) and sets up the Immutable X provider. /// This opens the user's default browser on desktop or an in-app browser on mobile. /// If true, Passport will attempt to re-authenticate the player using stored credentials. If re-authentication fails, it won't automatically prompt the user to log in again. - /// Optional direct login method to use (google, apple, facebook). If None, the user will see the standard login page. + /// Direct login options for authentication (defaults to email method). /// - public async UniTask ConnectImx(bool useCachedSession = false, DirectLoginMethod directLoginMethod = DirectLoginMethod.None) + public async UniTask ConnectImx(bool useCachedSession = false, DirectLoginOptions directLoginOptions = null) { - return await GetPassportImpl().ConnectImx(useCachedSession, directLoginMethod); + return await GetPassportImpl().ConnectImx(useCachedSession, directLoginOptions); } ///