From 906aeb16dd0d13d18b80a281b9f585a88e30df40 Mon Sep 17 00:00:00 2001 From: Robin Genz Date: Thu, 21 Jul 2022 20:21:09 +0200 Subject: [PATCH 01/10] wip: definitions --- packages/authentication/src/definitions.ts | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packages/authentication/src/definitions.ts b/packages/authentication/src/definitions.ts index fab14aaf..eaec8417 100644 --- a/packages/authentication/src/definitions.ts +++ b/packages/authentication/src/definitions.ts @@ -450,6 +450,12 @@ export interface SignInResult { * @since 0.1.0 */ credential: AuthCredential | null; + /** + * Additional user information from a federated identity provider. + * + * @since 0.5.1 + */ + additionalUserInfo: AdditionalUserInfo; } /** @@ -562,6 +568,36 @@ export interface AuthCredential { nonce?: string; } +/** + * @since 0.5.1 + */ +export interface AdditionalUserInfo { + /** + * Whether the user is new (sign-up) or existing (sign-in). + * + * @since 0.5.1 + */ + isNewUser?: boolean; + /** + * Map containing IDP-specific user data. + * + * @since 0.5.1 + */ + profile?: { [key: string]: unknown } + /** + * Identifier for the provider used to authenticate this user. + * + * @since 0.5.1 + */ + providerId: string | null; + /** + * The username if the provider is GitHub or Twitter. + * + * @since 0.5.1 + */ + username?: string | null; +} + /** * Callback to receive the user's sign-in state change notifications. * From 67a99c3231180b4a1721e15c4a8f04ed2f89532b Mon Sep 17 00:00:00 2001 From: Robin Genz Date: Sat, 23 Jul 2022 11:13:27 +0200 Subject: [PATCH 02/10] feat(web): implement `AdditionalUserInfo` --- packages/authentication/README.md | 19 +++- packages/authentication/src/definitions.ts | 16 +-- packages/authentication/src/web.ts | 112 ++++++++++++--------- 3 files changed, 89 insertions(+), 58 deletions(-) diff --git a/packages/authentication/README.md b/packages/authentication/README.md index e557d520..5c707759 100644 --- a/packages/authentication/README.md +++ b/packages/authentication/README.md @@ -777,10 +777,11 @@ Remove all listeners for this plugin. #### SignInResult -| Prop | Type | Description | Since | -| ---------------- | ----------------------------------------------------------------- | --------------------------------------------------------- | ----- | -| **`user`** | User \| null | The currently signed-in user, or null if there isn't any. | 0.1.0 | -| **`credential`** | AuthCredential \| null | Credentials returned by an auth provider. | 0.1.0 | +| Prop | Type | Description | Since | +| ------------------------ | ------------------------------------------------------------------------- | --------------------------------------------------------------- | ----- | +| **`user`** | User \| null | The currently signed-in user, or null if there isn't any. | 0.1.0 | +| **`credential`** | AuthCredential \| null | Credentials returned by an auth provider. | 0.1.0 | +| **`additionalUserInfo`** | AdditionalUserInfo \| null | Additional user information from a federated identity provider. | 0.5.1 | #### User @@ -809,6 +810,16 @@ Remove all listeners for this plugin. | **`nonce`** | string | The random string used to make sure that the ID token you get was granted specifically in response to your app's authentication request. | 0.1.0 | +#### AdditionalUserInfo + +| Prop | Type | Description | Since | +| ---------------- | ---------------------------------------- | ----------------------------------------------------------- | ----- | +| **`isNewUser`** | boolean | Whether the user is new (sign-up) or existing (sign-in). | 0.5.1 | +| **`profile`** | { [key: string]: unknown; } | Map containing IDP-specific user data. | 0.5.1 | +| **`providerId`** | string \| null | Identifier for the provider used to authenticate this user. | 0.5.1 | +| **`username`** | string \| null | The username if the provider is GitHub or Twitter. | 0.5.1 | + + #### CreateUserWithEmailAndPasswordOptions | Prop | Type | Since | diff --git a/packages/authentication/src/definitions.ts b/packages/authentication/src/definitions.ts index eaec8417..3731328c 100644 --- a/packages/authentication/src/definitions.ts +++ b/packages/authentication/src/definitions.ts @@ -452,10 +452,10 @@ export interface SignInResult { credential: AuthCredential | null; /** * Additional user information from a federated identity provider. - * + * * @since 0.5.1 */ - additionalUserInfo: AdditionalUserInfo; + additionalUserInfo: AdditionalUserInfo | null; } /** @@ -574,25 +574,25 @@ export interface AuthCredential { export interface AdditionalUserInfo { /** * Whether the user is new (sign-up) or existing (sign-in). - * + * * @since 0.5.1 */ - isNewUser?: boolean; + isNewUser: boolean; /** * Map containing IDP-specific user data. - * + * * @since 0.5.1 */ - profile?: { [key: string]: unknown } + profile?: { [key: string]: unknown }; /** * Identifier for the provider used to authenticate this user. - * + * * @since 0.5.1 */ providerId: string | null; /** * The username if the provider is GitHub or Twitter. - * + * * @since 0.5.1 */ username?: string | null; diff --git a/packages/authentication/src/web.ts b/packages/authentication/src/web.ts index 7dd76d8c..855bf3b8 100644 --- a/packages/authentication/src/web.ts +++ b/packages/authentication/src/web.ts @@ -2,9 +2,10 @@ import { WebPlugin } from '@capacitor/core'; import type { AuthCredential as FirebaseAuthCredential, User as FirebaseUser, - UserCredential, + UserCredential as FirebaseUserCredential, } from 'firebase/auth'; import { + getAdditionalUserInfo, applyActionCode, confirmPasswordReset, connectAuthEmulator, @@ -24,6 +25,7 @@ import { } from 'firebase/auth'; import type { + AdditionalUserInfo, ApplyActionCodeOptions, AuthCredential, AuthStateChange, @@ -66,12 +68,12 @@ export class FirebaseAuthenticationWeb options: CreateUserWithEmailAndPasswordOptions, ): Promise { const auth = getAuth(); - const credential = await createUserWithEmailAndPassword( + const userCredential = await createUserWithEmailAndPassword( auth, options.email, options.password, ); - return this.createSignInResultFromUserCredential(credential); + return this.createSignInResult(userCredential, null); } public async confirmPasswordReset( @@ -129,29 +131,29 @@ export class FirebaseAuthenticationWeb const provider = new OAuthProvider('apple.com'); this.applySignInOptions(options || {}, provider); const auth = getAuth(); - const result = await signInWithPopup(auth, provider); - const credential = OAuthProvider.credentialFromResult(result); - return this.createSignInResultFromAuthCredential(result.user, credential); + const userCredential = await signInWithPopup(auth, provider); + const authCredential = OAuthProvider.credentialFromResult(userCredential); + return this.createSignInResult(userCredential, authCredential); } public async signInWithCustomToken( options: SignInWithCustomTokenOptions, ): Promise { const auth = getAuth(); - const result = await signInWithCustomToken(auth, options.token); - return this.createSignInResultFromAuthCredential(result.user, null); + const userCredential = await signInWithCustomToken(auth, options.token); + return this.createSignInResult(userCredential, null); } public async signInWithEmailAndPassword( options: SignInWithEmailAndPasswordOptions, ): Promise { const auth = getAuth(); - const credential = await signInWithEmailAndPassword( + const userCredential = await signInWithEmailAndPassword( auth, options.email, options.password, ); - return this.createSignInResultFromUserCredential(credential); + return this.createSignInResult(userCredential, null); } public async signInWithFacebook( @@ -160,9 +162,11 @@ export class FirebaseAuthenticationWeb const provider = new FacebookAuthProvider(); this.applySignInOptions(options || {}, provider); const auth = getAuth(); - const result = await signInWithPopup(auth, provider); - const credential = FacebookAuthProvider.credentialFromResult(result); - return this.createSignInResultFromAuthCredential(result.user, credential); + const userCredential = await signInWithPopup(auth, provider); + const authCredential = FacebookAuthProvider.credentialFromResult( + userCredential, + ); + return this.createSignInResult(userCredential, authCredential); } public async signInWithGithub( @@ -171,9 +175,9 @@ export class FirebaseAuthenticationWeb const provider = new OAuthProvider('github.com'); this.applySignInOptions(options || {}, provider); const auth = getAuth(); - const result = await signInWithPopup(auth, provider); - const credential = OAuthProvider.credentialFromResult(result); - return this.createSignInResultFromAuthCredential(result.user, credential); + const userCredential = await signInWithPopup(auth, provider); + const authCredential = OAuthProvider.credentialFromResult(userCredential); + return this.createSignInResult(userCredential, authCredential); } public async signInWithGoogle( @@ -182,9 +186,11 @@ export class FirebaseAuthenticationWeb const provider = new GoogleAuthProvider(); this.applySignInOptions(options || {}, provider); const auth = getAuth(); - const result = await signInWithPopup(auth, provider); - const credential = GoogleAuthProvider.credentialFromResult(result); - return this.createSignInResultFromAuthCredential(result.user, credential); + const userCredential = await signInWithPopup(auth, provider); + const authCredential = GoogleAuthProvider.credentialFromResult( + userCredential, + ); + return this.createSignInResult(userCredential, authCredential); } public async signInWithMicrosoft( @@ -193,9 +199,9 @@ export class FirebaseAuthenticationWeb const provider = new OAuthProvider('microsoft.com'); this.applySignInOptions(options || {}, provider); const auth = getAuth(); - const result = await signInWithPopup(auth, provider); - const credential = OAuthProvider.credentialFromResult(result); - return this.createSignInResultFromAuthCredential(result.user, credential); + const userCredential = await signInWithPopup(auth, provider); + const authCredential = OAuthProvider.credentialFromResult(userCredential); + return this.createSignInResult(userCredential, authCredential); } public async signInWithPhoneNumber( @@ -214,18 +220,18 @@ export class FirebaseAuthenticationWeb const provider = new OAuthProvider('twitter.com'); this.applySignInOptions(options || {}, provider); const auth = getAuth(); - const result = await signInWithPopup(auth, provider); - const credential = OAuthProvider.credentialFromResult(result); - return this.createSignInResultFromAuthCredential(result.user, credential); + const userCredential = await signInWithPopup(auth, provider); + const authCredential = OAuthProvider.credentialFromResult(userCredential); + return this.createSignInResult(userCredential, authCredential); } public async signInWithYahoo(options?: SignInOptions): Promise { const provider = new OAuthProvider('yahoo.com'); this.applySignInOptions(options || {}, provider); const auth = getAuth(); - const result = await signInWithPopup(auth, provider); - const credential = OAuthProvider.credentialFromResult(result); - return this.createSignInResultFromAuthCredential(result.user, credential); + const userCredential = await signInWithPopup(auth, provider); + const authCredential = OAuthProvider.credentialFromResult(userCredential); + return this.createSignInResult(userCredential, authCredential); } public async signOut(): Promise { @@ -281,26 +287,19 @@ export class FirebaseAuthenticationWeb } } - private createSignInResultFromAuthCredential( - user: FirebaseUser, - credential: FirebaseAuthCredential | null, - ): SignInResult { - const userResult = this.createUserResult(user); - const credentialResult = this.createCredentialResult(credential); - const result: SignInResult = { - user: userResult, - credential: credentialResult, - }; - return result; - } - - private createSignInResultFromUserCredential( - credential: UserCredential, + private createSignInResult( + userCredential: FirebaseUserCredential, + authCredential: FirebaseAuthCredential | null, ): SignInResult { - const userResult = this.createUserResult(credential.user); + const user = this.createUserResult(userCredential.user); + const credential = this.createCredentialResult(authCredential); + const additionalUserInfo = this.createAdditionalUserInfoResult( + userCredential, + ); const result: SignInResult = { - user: userResult, - credential: null, + user, + credential, + additionalUserInfo, }; return result; } @@ -339,4 +338,25 @@ export class FirebaseAuthenticationWeb }; return result; } + + private createAdditionalUserInfoResult( + credential: FirebaseUserCredential, + ): AdditionalUserInfo | null { + const additionalUserInfo = getAdditionalUserInfo(credential); + if (!additionalUserInfo) { + return null; + } + const { isNewUser, profile, providerId, username } = additionalUserInfo; + const result: AdditionalUserInfo = { + isNewUser, + providerId, + }; + if (profile) { + result.profile = profile as { [key: string]: unknown }; + } + if (username !== undefined) { + result.username = username; + } + return result; + } } From 09d94fd8a3fd1ac733c001f0d81f31d2901e193b Mon Sep 17 00:00:00 2001 From: Robin Genz Date: Sat, 23 Jul 2022 12:06:22 +0200 Subject: [PATCH 03/10] feat(android): implement `AdditionalUserInfo` --- .../FirebaseAuthentication.java | 33 +++++++++++-------- .../FirebaseAuthenticationHelper.java | 27 ++++++++++++++- .../handlers/AppleAuthProviderHandler.java | 7 ++-- .../handlers/FacebookAuthProviderHandler.java | 2 +- .../handlers/GoogleAuthProviderHandler.java | 2 +- .../handlers/OAuthProviderHandler.java | 8 +++-- .../handlers/PhoneAuthProviderHandler.java | 6 ++-- .../PlayGamesAuthProviderHandler.java | 2 +- packages/authentication/src/definitions.ts | 5 ++- packages/authentication/src/web.ts | 20 ++++++----- 10 files changed, 75 insertions(+), 37 deletions(-) diff --git a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthentication.java b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthentication.java index 8a619085..d68f8c73 100644 --- a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthentication.java +++ b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthentication.java @@ -8,7 +8,9 @@ import com.getcapacitor.JSObject; import com.getcapacitor.PluginCall; import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.AdditionalUserInfo; import com.google.firebase.auth.AuthCredential; +import com.google.firebase.auth.AuthResult; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.FirebaseUser; import com.google.firebase.auth.GetTokenResult; @@ -100,7 +102,7 @@ public void createUserWithEmailAndPassword(PluginCall call) { if (task.isSuccessful()) { Log.d(FirebaseAuthenticationPlugin.TAG, "createUserWithEmailAndPassword succeeded."); FirebaseUser user = getCurrentUser(); - JSObject signInResult = FirebaseAuthenticationHelper.createSignInResult(user, null, null, null, null); + JSObject signInResult = FirebaseAuthenticationHelper.createSignInResult(user, null, null, null, null, null); call.resolve(signInResult); } else { Log.e(FirebaseAuthenticationPlugin.TAG, "createUserWithEmailAndPassword failed.", task.getException()); @@ -222,7 +224,7 @@ public void signInWithCustomToken(final PluginCall call) { if (task.isSuccessful()) { Log.d(FirebaseAuthenticationPlugin.TAG, "signInWithCustomToken succeeded."); FirebaseUser user = getCurrentUser(); - JSObject signInResult = FirebaseAuthenticationHelper.createSignInResult(user, null, null, null, null); + JSObject signInResult = FirebaseAuthenticationHelper.createSignInResult(user, null, null, null, null, null); call.resolve(signInResult); } else { Log.e(FirebaseAuthenticationPlugin.TAG, "signInWithCustomToken failed.", task.getException()); @@ -250,7 +252,7 @@ public void signInWithEmailAndPassword(final PluginCall call) { if (task.isSuccessful()) { Log.d(FirebaseAuthenticationPlugin.TAG, "signInWithEmailAndPassword succeeded."); FirebaseUser user = getCurrentUser(); - JSObject signInResult = FirebaseAuthenticationHelper.createSignInResult(user, null, null, null, null); + JSObject signInResult = FirebaseAuthenticationHelper.createSignInResult(user, null, null, null, null, null); call.resolve(signInResult); } else { Log.e(FirebaseAuthenticationPlugin.TAG, "signInWithEmailAndPassword failed.", task.getException()); @@ -320,20 +322,24 @@ public void handleOnActivityResult(int requestCode, int resultCode, Intent data) } } - public void handleSuccessfulSignIn(final PluginCall call, AuthCredential credential, String idToken) { - handleSuccessfulSignIn(call, credential, idToken, null, null); - } - public void handleSuccessfulSignIn( final PluginCall call, @Nullable AuthCredential credential, @Nullable String idToken, @Nullable String nonce, - @Nullable String accessToken + @Nullable String accessToken, + @Nullable AdditionalUserInfo additionalUserInfo ) { boolean skipNativeAuth = this.config.getSkipNativeAuth(); if (skipNativeAuth) { - JSObject signInResult = FirebaseAuthenticationHelper.createSignInResult(null, credential, idToken, nonce, accessToken); + JSObject signInResult = FirebaseAuthenticationHelper.createSignInResult( + null, + credential, + idToken, + nonce, + accessToken, + additionalUserInfo + ); call.resolve(signInResult); return; } @@ -344,13 +350,14 @@ public void handleSuccessfulSignIn( task -> { if (task.isSuccessful()) { Log.d(FirebaseAuthenticationPlugin.TAG, "signInWithCredential succeeded."); - FirebaseUser user = getCurrentUser(); + AuthResult authResult = task.getResult(); JSObject signInResult = FirebaseAuthenticationHelper.createSignInResult( - user, - credential, + authResult.getUser(), + authResult.getCredential(), idToken, nonce, - accessToken + accessToken, + authResult.getAdditionalUserInfo() ); call.resolve(signInResult); } else { diff --git a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthenticationHelper.java b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthenticationHelper.java index 51a37cce..ebe72c11 100644 --- a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthenticationHelper.java +++ b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthenticationHelper.java @@ -2,6 +2,7 @@ import androidx.annotation.Nullable; import com.getcapacitor.JSObject; +import com.google.firebase.auth.AdditionalUserInfo; import com.google.firebase.auth.AuthCredential; import com.google.firebase.auth.FirebaseUser; import com.google.firebase.auth.OAuthCredential; @@ -13,16 +14,20 @@ public static JSObject createSignInResult( @Nullable AuthCredential credential, @Nullable String idToken, @Nullable String nonce, - @Nullable String accessToken + @Nullable String accessToken, + @Nullable AdditionalUserInfo additionalUserInfo ) { JSObject userResult = FirebaseAuthenticationHelper.createUserResult(user); JSObject credentialResult = FirebaseAuthenticationHelper.createCredentialResult(credential, idToken, nonce, accessToken); + JSObject additionalUserInfoResult = FirebaseAuthenticationHelper.createAdditionalUserInfoResult(additionalUserInfo); JSObject result = new JSObject(); result.put("user", userResult); result.put("credential", credentialResult); + result.put("additionalUserInfo", additionalUserInfoResult); return result; } + @Nullable public static JSObject createUserResult(@Nullable FirebaseUser user) { if (user == null) { return null; @@ -40,6 +45,7 @@ public static JSObject createUserResult(@Nullable FirebaseUser user) { return result; } + @Nullable public static JSObject createCredentialResult( @Nullable AuthCredential credential, @Nullable String idToken, @@ -78,4 +84,23 @@ public static JSObject createCredentialResult( } return result; } + + @Nullable + public static JSObject createAdditionalUserInfoResult(@Nullable AdditionalUserInfo additionalUserInfo) { + if (additionalUserInfo == null) { + return null; + } + JSObject result = new JSObject(); + result.put("isNewUser", additionalUserInfo.isNewUser()); + if (additionalUserInfo.getProfile() != null) { + result.put("profile", additionalUserInfo.getProfile()); + } + if (additionalUserInfo.getProviderId() != null) { + result.put("providerId", additionalUserInfo.getProviderId()); + } + if (additionalUserInfo.getUsername() != null) { + result.put("username", additionalUserInfo.getUsername()); + } + return result; + } } diff --git a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/AppleAuthProviderHandler.java b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/AppleAuthProviderHandler.java index 7b555e0b..4173b6ac 100644 --- a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/AppleAuthProviderHandler.java +++ b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/AppleAuthProviderHandler.java @@ -5,6 +5,7 @@ import com.getcapacitor.JSObject; import com.getcapacitor.PluginCall; import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.AdditionalUserInfo; import com.google.firebase.auth.AuthCredential; import com.google.firebase.auth.AuthResult; import com.google.firebase.auth.OAuthProvider; @@ -86,7 +87,8 @@ private void startActivityForSignIn(final PluginCall call, OAuthProvider.Builder .addOnSuccessListener( authResult -> { AuthCredential credential = authResult.getCredential(); - pluginImplementation.handleSuccessfulSignIn(call, credential, null, currentNonce, null); + AdditionalUserInfo additionalUserInfo = authResult.getAdditionalUserInfo(); + pluginImplementation.handleSuccessfulSignIn(call, credential, null, currentNonce, null, additionalUserInfo); } ) .addOnFailureListener(exception -> pluginImplementation.handleFailedSignIn(call, null, exception)); @@ -97,7 +99,8 @@ private void finishActivityForSignIn(final PluginCall call, Task pen .addOnSuccessListener( authResult -> { AuthCredential credential = authResult.getCredential(); - pluginImplementation.handleSuccessfulSignIn(call, credential, null, currentNonce, null); + AdditionalUserInfo additionalUserInfo = authResult.getAdditionalUserInfo(); + pluginImplementation.handleSuccessfulSignIn(call, credential, null, currentNonce, null, additionalUserInfo); } ) .addOnFailureListener(exception -> pluginImplementation.handleFailedSignIn(call, null, exception)); diff --git a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/FacebookAuthProviderHandler.java b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/FacebookAuthProviderHandler.java index 27167fec..85157d36 100644 --- a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/FacebookAuthProviderHandler.java +++ b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/FacebookAuthProviderHandler.java @@ -97,7 +97,7 @@ private void handleSuccessCallback(LoginResult loginResult) { if (savedCall == null) { return; } - pluginImplementation.handleSuccessfulSignIn(savedCall, credential, null, null, accessTokenString); + pluginImplementation.handleSuccessfulSignIn(savedCall, credential, null, null, accessTokenString, null); } private void handleCancelCallback() { diff --git a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/GoogleAuthProviderHandler.java b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/GoogleAuthProviderHandler.java index 21bc9274..c990aef7 100644 --- a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/GoogleAuthProviderHandler.java +++ b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/GoogleAuthProviderHandler.java @@ -65,7 +65,7 @@ public void handleOnActivityResult(final PluginCall call, ActivityResult result) pluginImplementation.handleFailedSignIn(call, null, exception); } - pluginImplementation.handleSuccessfulSignIn(call, credential, idToken, null, accessToken); + pluginImplementation.handleSuccessfulSignIn(call, credential, idToken, null, accessToken, null); } ) .start(); diff --git a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/OAuthProviderHandler.java b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/OAuthProviderHandler.java index 26ff7340..85476e2d 100644 --- a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/OAuthProviderHandler.java +++ b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/OAuthProviderHandler.java @@ -5,9 +5,9 @@ import com.getcapacitor.JSObject; import com.getcapacitor.PluginCall; import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.AdditionalUserInfo; import com.google.firebase.auth.AuthCredential; import com.google.firebase.auth.AuthResult; -import com.google.firebase.auth.OAuthCredential; import com.google.firebase.auth.OAuthProvider; import dev.robingenz.capacitorjs.plugins.firebase.authentication.FirebaseAuthentication; import dev.robingenz.capacitorjs.plugins.firebase.authentication.FirebaseAuthenticationPlugin; @@ -41,7 +41,8 @@ private void startActivityForSignIn(final PluginCall call, OAuthProvider.Builder .addOnSuccessListener( authResult -> { AuthCredential credential = authResult.getCredential(); - pluginImplementation.handleSuccessfulSignIn(call, credential, null); + AdditionalUserInfo additionalUserInfo = authResult.getAdditionalUserInfo(); + pluginImplementation.handleSuccessfulSignIn(call, credential, null, null, null, additionalUserInfo); } ) .addOnFailureListener(exception -> pluginImplementation.handleFailedSignIn(call, null, exception)); @@ -52,7 +53,8 @@ private void finishActivityForSignIn(final PluginCall call, Task pen .addOnSuccessListener( authResult -> { AuthCredential credential = authResult.getCredential(); - pluginImplementation.handleSuccessfulSignIn(call, credential, null); + AdditionalUserInfo additionalUserInfo = authResult.getAdditionalUserInfo(); + pluginImplementation.handleSuccessfulSignIn(call, credential, null, null, null, additionalUserInfo); } ) .addOnFailureListener(exception -> pluginImplementation.handleFailedSignIn(call, null, exception)); diff --git a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/PhoneAuthProviderHandler.java b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/PhoneAuthProviderHandler.java index 939e090d..584fdc07 100644 --- a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/PhoneAuthProviderHandler.java +++ b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/PhoneAuthProviderHandler.java @@ -44,14 +44,14 @@ private void verifyPhoneNumber(final PluginCall call, String phoneNumber) { private void handleVerificationCode(final PluginCall call, String verificationId, String verificationCode) { PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, verificationCode); - pluginImplementation.handleSuccessfulSignIn(call, credential, null); + pluginImplementation.handleSuccessfulSignIn(call, credential, null, null, null, null); } private PhoneAuthProvider.OnVerificationStateChangedCallbacks createCallbacks(final PluginCall call) { return new PhoneAuthProvider.OnVerificationStateChangedCallbacks() { @Override public void onVerificationCompleted(PhoneAuthCredential credential) { - pluginImplementation.handleSuccessfulSignIn(call, credential, null); + pluginImplementation.handleSuccessfulSignIn(call, credential, null, null, null, null); } @Override @@ -61,7 +61,7 @@ public void onVerificationFailed(FirebaseException exception) { @Override public void onCodeSent(@NonNull String verificationId, @NonNull PhoneAuthProvider.ForceResendingToken token) { - JSObject result = FirebaseAuthenticationHelper.createSignInResult(null, null, null, null, null); + JSObject result = FirebaseAuthenticationHelper.createSignInResult(null, null, null, null, null, null); result.put("verificationId", verificationId); call.resolve(result); } diff --git a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/PlayGamesAuthProviderHandler.java b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/PlayGamesAuthProviderHandler.java index 48fe83e3..481347b8 100644 --- a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/PlayGamesAuthProviderHandler.java +++ b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/handlers/PlayGamesAuthProviderHandler.java @@ -49,7 +49,7 @@ public void handleOnActivityResult(final PluginCall call, ActivityResult result) String serverAuthCode = account.getServerAuthCode(); AuthCredential credential = PlayGamesAuthProvider.getCredential(serverAuthCode); String idToken = account.getIdToken(); - pluginImplementation.handleSuccessfulSignIn(call, credential, idToken); + pluginImplementation.handleSuccessfulSignIn(call, credential, idToken, null, null, null); } catch (ApiException exception) { pluginImplementation.handleFailedSignIn(call, null, exception); } diff --git a/packages/authentication/src/definitions.ts b/packages/authentication/src/definitions.ts index 3731328c..80c6dfe1 100644 --- a/packages/authentication/src/definitions.ts +++ b/packages/authentication/src/definitions.ts @@ -589,15 +589,14 @@ export interface AdditionalUserInfo { * * @since 0.5.1 */ - providerId: string | null; + providerId?: string; /** * The username if the provider is GitHub or Twitter. * * @since 0.5.1 */ - username?: string | null; + username?: string; } - /** * Callback to receive the user's sign-in state change notifications. * diff --git a/packages/authentication/src/web.ts b/packages/authentication/src/web.ts index 855bf3b8..c2578927 100644 --- a/packages/authentication/src/web.ts +++ b/packages/authentication/src/web.ts @@ -291,15 +291,15 @@ export class FirebaseAuthenticationWeb userCredential: FirebaseUserCredential, authCredential: FirebaseAuthCredential | null, ): SignInResult { - const user = this.createUserResult(userCredential.user); - const credential = this.createCredentialResult(authCredential); - const additionalUserInfo = this.createAdditionalUserInfoResult( + const userResult = this.createUserResult(userCredential.user); + const credentialResult = this.createCredentialResult(authCredential); + const additionalUserInfoResult = this.createAdditionalUserInfoResult( userCredential, ); const result: SignInResult = { - user, - credential, - additionalUserInfo, + user: userResult, + credential: credentialResult, + additionalUserInfo: additionalUserInfoResult, }; return result; } @@ -349,12 +349,14 @@ export class FirebaseAuthenticationWeb const { isNewUser, profile, providerId, username } = additionalUserInfo; const result: AdditionalUserInfo = { isNewUser, - providerId, }; - if (profile) { + if (providerId !== null) { + result.providerId = providerId; + } + if (profile !== null) { result.profile = profile as { [key: string]: unknown }; } - if (username !== undefined) { + if (username !== null && username !== undefined) { result.username = username; } return result; From d1b7372aa086987c6451b32671849ab064dadb2e Mon Sep 17 00:00:00 2001 From: Robin Genz Date: Sat, 23 Jul 2022 13:46:38 +0200 Subject: [PATCH 04/10] feat(ios): implement `AdditionalUserInfo` --- .../ios/Plugin/FirebaseAuthentication.swift | 11 +++++----- .../Plugin/FirebaseAuthenticationHelper.swift | 20 ++++++++++++++++++- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/packages/authentication/ios/Plugin/FirebaseAuthentication.swift b/packages/authentication/ios/Plugin/FirebaseAuthentication.swift index a7e33922..d6206b5d 100644 --- a/packages/authentication/ios/Plugin/FirebaseAuthentication.swift +++ b/packages/authentication/ios/Plugin/FirebaseAuthentication.swift @@ -60,7 +60,7 @@ public typealias AuthStateChangedObserver = () -> Void return } let user = self.getCurrentUser() - let result = FirebaseAuthenticationHelper.createSignInResult(credential: nil, user: user, idToken: nil, nonce: nil, accessToken: nil) + let result = FirebaseAuthenticationHelper.createSignInResult(credential: nil, user: user, idToken: nil, nonce: nil, accessToken: nil, additionalUserInfo: nil) savedCall.resolve(result) } } @@ -128,7 +128,7 @@ public typealias AuthStateChangedObserver = () -> Void return } let user = self.getCurrentUser() - let result = FirebaseAuthenticationHelper.createSignInResult(credential: nil, user: user, idToken: nil, nonce: nil, accessToken: nil) + let result = FirebaseAuthenticationHelper.createSignInResult(credential: nil, user: user, idToken: nil, nonce: nil, accessToken: nil, additionalUserInfo: nil) savedCall.resolve(result) } } @@ -152,7 +152,7 @@ public typealias AuthStateChangedObserver = () -> Void return } let user = self.getCurrentUser() - let result = FirebaseAuthenticationHelper.createSignInResult(credential: nil, user: user, idToken: nil, nonce: nil, accessToken: nil) + let result = FirebaseAuthenticationHelper.createSignInResult(credential: nil, user: user, idToken: nil, nonce: nil, accessToken: nil, additionalUserInfo: nil) savedCall.resolve(result) } } @@ -228,7 +228,7 @@ public typealias AuthStateChangedObserver = () -> Void guard let savedCall = self.savedCall else { return } - let result = FirebaseAuthenticationHelper.createSignInResult(credential: credential, user: nil, idToken: idToken, nonce: nonce, accessToken: accessToken) + let result = FirebaseAuthenticationHelper.createSignInResult(credential: credential, user: nil, idToken: idToken, nonce: nonce, accessToken: accessToken, additionalUserInfo: nil) savedCall.resolve(result) return } @@ -240,8 +240,7 @@ public typealias AuthStateChangedObserver = () -> Void guard let savedCall = self.savedCall else { return } - let user = self.getCurrentUser() - let result = FirebaseAuthenticationHelper.createSignInResult(credential: authResult?.credential, user: user, idToken: idToken, nonce: nonce, accessToken: accessToken) + let result = FirebaseAuthenticationHelper.createSignInResult(credential: authResult?.credential, user: authResult?.user, idToken: idToken, nonce: nonce, accessToken: accessToken, additionalUserInfo: authResult?.additionalUserInfo) savedCall.resolve(result) } } diff --git a/packages/authentication/ios/Plugin/FirebaseAuthenticationHelper.swift b/packages/authentication/ios/Plugin/FirebaseAuthenticationHelper.swift index 9ae432ee..dfcc8b7e 100644 --- a/packages/authentication/ios/Plugin/FirebaseAuthenticationHelper.swift +++ b/packages/authentication/ios/Plugin/FirebaseAuthenticationHelper.swift @@ -4,12 +4,14 @@ import FirebaseCore import FirebaseAuth public class FirebaseAuthenticationHelper { - public static func createSignInResult(credential: AuthCredential?, user: User?, idToken: String?, nonce: String?, accessToken: String?) -> JSObject { + public static func createSignInResult(credential: AuthCredential?, user: User?, idToken: String?, nonce: String?, accessToken: String?, additionalUserInfo: AdditionalUserInfo?) -> JSObject { let userResult = self.createUserResult(user) let credentialResult = self.createCredentialResult(credential, idToken: idToken, nonce: nonce, accessToken: accessToken) + let additionalUserInfoResult = self.createAdditionalUserInfoResult(additionalUserInfo) var result = JSObject() result["user"] = userResult result["credential"] = credentialResult + result["additionalUserInfo"] = additionalUserInfoResult return result } @@ -63,4 +65,20 @@ public class FirebaseAuthenticationHelper { } return result } + + public static func createAdditionalUserInfoResult(_ additionalUserInfo: AdditionalUserInfo?) -> JSObject? { + guard let additionalUserInfo = additionalUserInfo else { + return nil + } + var result = JSObject() + result["isNewUser"] = additionalUserInfo.isNewUser + if let profile = additionalUserInfo.profile { + result["profile"] = JSTypes.coerceDictionaryToJSObject(profile) ?? [:] + } + result["providerId"] = additionalUserInfo.providerID + if let username = additionalUserInfo.username { + result["username"] = username + } + return result + } } From cabe513bdf056c7d1c7c828dad9b637269dea4dc Mon Sep 17 00:00:00 2001 From: Robin Genz Date: Sat, 23 Jul 2022 13:50:52 +0200 Subject: [PATCH 05/10] docs --- packages/authentication/README.md | 6 +++--- packages/authentication/src/definitions.ts | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/authentication/README.md b/packages/authentication/README.md index 5c707759..0cbcd729 100644 --- a/packages/authentication/README.md +++ b/packages/authentication/README.md @@ -60,7 +60,7 @@ These configuration values are available: | Prop | Type | Description | Default | Since | | -------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | -| **`skipNativeAuth`** | boolean | Configure whether the plugin should skip the native authentication. Only needed if you want to use the Firebase JavaScript SDK. Only available for Android and iOS. | false | 0.1.0 | +| **`skipNativeAuth`** | boolean | Configure whether the plugin should skip the native authentication. Only needed if you want to use the Firebase JavaScript SDK. **Note that the plugin may behave differently across the platforms.** Only available for Android and iOS. | false | 0.1.0 | | **`providers`** | string[] | Configure which providers you want to use so that only the providers you need are fully initialized. If you do not configure any providers, they will be all initialized. Please note that this does not prevent the automatic initialization of third-party SDKs. Only available for Android and iOS. | ["apple.com", "facebook.com", "github.com", "google.com", "microsoft.com", "playgames.google.com", "twitter.com", "yahoo.com", "phone"] | 0.1.0 | ### Examples @@ -816,8 +816,8 @@ Remove all listeners for this plugin. | ---------------- | ---------------------------------------- | ----------------------------------------------------------- | ----- | | **`isNewUser`** | boolean | Whether the user is new (sign-up) or existing (sign-in). | 0.5.1 | | **`profile`** | { [key: string]: unknown; } | Map containing IDP-specific user data. | 0.5.1 | -| **`providerId`** | string \| null | Identifier for the provider used to authenticate this user. | 0.5.1 | -| **`username`** | string \| null | The username if the provider is GitHub or Twitter. | 0.5.1 | +| **`providerId`** | string | Identifier for the provider used to authenticate this user. | 0.5.1 | +| **`username`** | string | The username if the provider is GitHub or Twitter. | 0.5.1 | #### CreateUserWithEmailAndPasswordOptions diff --git a/packages/authentication/src/definitions.ts b/packages/authentication/src/definitions.ts index 80c6dfe1..f40b7c80 100644 --- a/packages/authentication/src/definitions.ts +++ b/packages/authentication/src/definitions.ts @@ -14,6 +14,8 @@ declare module '@capacitor/cli' { * Configure whether the plugin should skip the native authentication. * Only needed if you want to use the Firebase JavaScript SDK. * + * **Note that the plugin may behave differently across the platforms.** + * * Only available for Android and iOS. * * @default false From b60b25471b8f96d5b5bce37cfdae3e86ae830453 Mon Sep 17 00:00:00 2001 From: Robin Genz Date: Sat, 23 Jul 2022 14:00:48 +0200 Subject: [PATCH 06/10] fix build --- .../ios/Plugin/Handlers/PhoneAuthProviderHandler.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/authentication/ios/Plugin/Handlers/PhoneAuthProviderHandler.swift b/packages/authentication/ios/Plugin/Handlers/PhoneAuthProviderHandler.swift index db12224c..07305570 100644 --- a/packages/authentication/ios/Plugin/Handlers/PhoneAuthProviderHandler.swift +++ b/packages/authentication/ios/Plugin/Handlers/PhoneAuthProviderHandler.swift @@ -34,7 +34,7 @@ class PhoneAuthProviderHandler: NSObject { return } - var result = FirebaseAuthenticationHelper.createSignInResult(credential: nil, user: nil, idToken: nil, nonce: nil, accessToken: nil) + var result = FirebaseAuthenticationHelper.createSignInResult(credential: nil, user: nil, idToken: nil, nonce: nil, accessToken: nil, additionalUserInfo: nil) result["verificationId"] = verificationID call.resolve(result) } From d71c8ae7f90166f8d12635d4d1ca9de939a70011 Mon Sep 17 00:00:00 2001 From: Robin Genz Date: Sat, 23 Jul 2022 14:14:02 +0200 Subject: [PATCH 07/10] fix lint error --- .../authentication/ios/Plugin/FirebaseAuthentication.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/authentication/ios/Plugin/FirebaseAuthentication.swift b/packages/authentication/ios/Plugin/FirebaseAuthentication.swift index d6206b5d..f3ccc83d 100644 --- a/packages/authentication/ios/Plugin/FirebaseAuthentication.swift +++ b/packages/authentication/ios/Plugin/FirebaseAuthentication.swift @@ -240,7 +240,8 @@ public typealias AuthStateChangedObserver = () -> Void guard let savedCall = self.savedCall else { return } - let result = FirebaseAuthenticationHelper.createSignInResult(credential: authResult?.credential, user: authResult?.user, idToken: idToken, nonce: nonce, accessToken: accessToken, additionalUserInfo: authResult?.additionalUserInfo) + let result = FirebaseAuthenticationHelper.createSignInResult(credential: authResult?.credential, user: authResult?.user, idToken: idToken, + nonce: nonce, accessToken: accessToken, additionalUserInfo: authResult?.additionalUserInfo) savedCall.resolve(result) } } From afeddcc1421366c4bf08a8b2a3ef0cf555a2299a Mon Sep 17 00:00:00 2001 From: Robin Genz Date: Sat, 23 Jul 2022 14:46:25 +0200 Subject: [PATCH 08/10] fix(android) --- .../authentication/FirebaseAuthenticationHelper.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthenticationHelper.java b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthenticationHelper.java index ebe72c11..5c745914 100644 --- a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthenticationHelper.java +++ b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthenticationHelper.java @@ -7,6 +7,8 @@ import com.google.firebase.auth.FirebaseUser; import com.google.firebase.auth.OAuthCredential; +import java.util.Map; + public class FirebaseAuthenticationHelper { public static JSObject createSignInResult( @@ -93,7 +95,11 @@ public static JSObject createAdditionalUserInfoResult(@Nullable AdditionalUserIn JSObject result = new JSObject(); result.put("isNewUser", additionalUserInfo.isNewUser()); if (additionalUserInfo.getProfile() != null) { - result.put("profile", additionalUserInfo.getProfile()); + JSObject profileResult = new JSObject(); + for (Map.Entry entry : additionalUserInfo.getProfile().entrySet()) { + profileResult.put(entry.getKey(), entry.getValue()); + } + result.put("profile", profileResult); } if (additionalUserInfo.getProviderId() != null) { result.put("providerId", additionalUserInfo.getProviderId()); From 3e2d3087b89ac277e19e077792507d8745ec234a Mon Sep 17 00:00:00 2001 From: Robin Genz Date: Sat, 23 Jul 2022 14:55:37 +0200 Subject: [PATCH 09/10] style: fmt --- .../firebase/authentication/FirebaseAuthenticationHelper.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthenticationHelper.java b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthenticationHelper.java index 5c745914..00d953a6 100644 --- a/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthenticationHelper.java +++ b/packages/authentication/android/src/main/java/dev/robingenz/capacitorjs/plugins/firebase/authentication/FirebaseAuthenticationHelper.java @@ -6,7 +6,6 @@ import com.google.firebase.auth.AuthCredential; import com.google.firebase.auth.FirebaseUser; import com.google.firebase.auth.OAuthCredential; - import java.util.Map; public class FirebaseAuthenticationHelper { @@ -97,7 +96,7 @@ public static JSObject createAdditionalUserInfoResult(@Nullable AdditionalUserIn if (additionalUserInfo.getProfile() != null) { JSObject profileResult = new JSObject(); for (Map.Entry entry : additionalUserInfo.getProfile().entrySet()) { - profileResult.put(entry.getKey(), entry.getValue()); + profileResult.put(entry.getKey(), entry.getValue()); } result.put("profile", profileResult); } From 218bb818cea1c2b35eec2ac8a0f4e5f14ec907e0 Mon Sep 17 00:00:00 2001 From: Robin Genz Date: Sat, 23 Jul 2022 14:56:49 +0200 Subject: [PATCH 10/10] docs --- .changeset/small-fishes-end.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/small-fishes-end.md diff --git a/.changeset/small-fishes-end.md b/.changeset/small-fishes-end.md new file mode 100644 index 00000000..c2dbb200 --- /dev/null +++ b/.changeset/small-fishes-end.md @@ -0,0 +1,5 @@ +--- +"@capacitor-firebase/authentication": patch +--- + +feat: expose `AdditionalUserInfo`