capawesome-team / capacitor-firebase

⚡️ Firebase plugins for Capacitor. Supports Android, iOS and the Web.

Home Page:https://capawesome.io/plugins/firebase/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

bug: signInWithApple() and skinNative:true doesn't trigger user change when logging in.

woutersteven opened this issue · comments

Plugin(s)

  • Analytics
  • App
  • App Check
  • Authentication
  • Crashlytics
  • Cloud Firestore
  • Cloud Messaging
  • Cloud Storage
  • Performance
  • Remote Config

Version

5.4.0

Platform(s)

  • Android
  • iOS
  • Web

Current behavior

When using signInWithApple() and "skipNativeAuth: true", the login seems to work, but the user doesn't get changed. It works with PDA and Android. I've tested it with both AngularFire (v17.0.1) and Firebase packages (v10.7.2). The result is the same. A credential seems to appear, but there is no user being set. authStateChange isn't triggered.

The same setup (but with skinNativeAuth: false) for Google works fine. Though the code is slightly different for Google with regards to logging in to the web layer.

The very weird thing is that i've seen it work a few times... maybe 5 out of 100 times and not able to determine why.

    public async signInWithApple(): Promise<void> {
        try {
            await FirebaseAuthentication.signInWithApple({
                scopes: ['email', 'name'],
                skipNativeAuth: true
            }).then(async (result) => {
                console.log("Native Login result: ", result);
                const credential = await new OAuthProvider("apple.com").credential({
                    idToken: result.credential?.idToken,
                    rawNonce: result.credential?.nonce,
                })
                const auth = await getAuth();
                const userCredential = await signInWithCredential(auth, credential);
                console.log("Credentials: ", userCredential);
            });
        } catch (error) {
            this.debugService.error('Error: Signing in with Apple on the Web layer...', error);
        }
    } // End of signInWithApple

In main.ts provideAuth is:

        provideAuth(() => {
          if (Capacitor.isNativePlatform()) {
            return initializeAuth(getApp(), {
              persistence: indexedDBLocalPersistence
            });
          }
          else {
            const auth = getAuth();
            return auth;
          }
        }),

It's used as in the examples provided:

    private async signInWith(provider: SignInProvider): Promise<void> {
        const loadingElement = await this.promptService.showLoading();
        try {
            switch (provider) {
                case SignInProvider.apple:
                    await this.auth.signInWithApple();
                    break;
                case SignInProvider.google:
                    await this.auth.signInWithGoogle();
                    break;
            }
            await this.navigateToHome();
        } finally {
            await loadingElement.dismiss();
        }
    }

Expected behavior

I'm expecting the user to be set, or an error message to be shown in the console.

Reproduction

None available

Steps to reproduce

It's possible I'm missing something or not understanding correctly.

Other information

Console logs to show that the login itself seems to work

`
{"credential":{"nonce":"6I3Nm7l0mQnu.bC58B3og4vObJUi2MjJ","idToken":"eyJraWQiOiJsVkhkT3g4bHRSIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoibmwubm92ZWxhcHByb2FjaGVzLmFpYW1hIiwiZXhwIjoxNzA2NTY5MTU5LCJpYXQiOjE3MDY0ODI3NTksInN1

⚡️ [log] - Native Login result: {"credential":{"nonce":"6I3Nm7l0mQnu.bC58B3og4vObJUi2MjJ","idToken":"eyJraWQiOiJsVkhkT3g4bHRSIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoibmwubm92ZWxhcHByb2FjaGVzLmFpYW1hIiwiZXhwIjoxNzA2NTY5MTU5LCJpYXQiOjE3MDY0ODI3NTksInN1YiI6IjAwMTA4NS4yZTU4MDI5OWJhYzU0ODlmOWRlYTMyNmNjNDM0MWEyZi4yMTU2Iiwibm9uY2UiOiI2YjkwZjdjMTFjZTlkMGI3OGJlZDNlODc5ZTQ5NGM4MDRkNWY0Y2NjMmFlYmNhZjI3OTFmMGMyNjY2NDcyZTIyIiwiY19oYXNoIjoid0RBVDl4TklXbEo4V3JoRldkbFdpdyIsImVtYWlsIjoic3VwcG9ydEBub3ZlbGFwcHJvYWNoZXMubmwiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJhdXRoX3RpbWUiOjE3MDY0ODI3NTksIm5vbmNlX3N1cHBvcnRlZCI6dHJ1ZX0.bE1c7kVYLyA1fZaLXNIv_E701fZaM8EqvB_xoJwJzd8tZfvYlxVqu5bC_ZfWkfv1UUbQrmXyZCgzdfmKYB916tYBWoyPcZ82-B1dV_tdOM2ofJwtjYYoofqs7_CicQwd8t0pC1NkMYWOx3EGifVl2SvLHRnvY2tc3M-46uG6j_dzIeO-1HQnGo5t4QX1vDNPGdTFT_03p9uqGPWzU63EN5JHey7vT6zZQ-q-zu1LeihcdoYpYBxet841ihKxL8SIwOVd586dIxafrNjaFihDhiZPPBRZU-60zdF5rXev9n_22hDnqqauxpZ9VU8HaQ7e1pC95SpCKnvaBHVXMw_dwA","authorizationCode":"c880d76c8db834603981f31cfbeef1add.0.rrqyv.pcTzrAjmAV8UlYQJcCpv9Q","providerId":"apple.com"},"additionalUserInfo":null,"user":null}

⚡️ [log] - Credentials: {"user":{"uid":"klQe68VHligY3T06GUYbnXcYKO23","email":"email@email.com","emailVerified":true,"isAnonymous":false,"providerData":[{"providerId":"apple.com","uid":"001085.2e580299bac5489f9dea326cc4341a2f.2156","displayName":null,"email":"email@email.com","phoneNumber":null,"photoURL":null}],"stsTokenManager":{"refreshToken":"AMf-vBybz5V8HnHGFxHoX2ZBRMbxM06QcCXfOVB1HQYtlBlrvnLKcma7G84OkaZXt5zaBJ3XrEwhMxJmrjQnqJTmSvWRk4Gfh9AsubOh8gwhjkc5mcsWkoVaxrVMmtB4XQ07cMud9kb7ytV03sicwu0kDH7UcF8YdjOw348EfaVr5krxoj7Pq5bWUW_3UgY1A2aVuo3GsyqOlj6OcP6WHRaMKBVvYJfshw4H0HZ1sVKjHDp4CI3YaUHaZFzez2LTu2ERuvN7gRpn074wsDV4teeKB-R4uQmUmg","accessToken":"eyJhbGciOiJSUzI1NiIsImtpZCI6IjY5NjI5NzU5NmJiNWQ4N2NjOTc2Y2E2YmY0Mzc3NGE3YWE5OTMxMjkiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vbmEtYWlhbWEiLCJhdWQiOiJuYS1haWFtYSIsImF1dGhfdGltZSI6MTcwNjQ4Mjc2MCwidXNlcl9pZCI6ImtsUWU2OFZIbGlnWTNUMDZHVVliblhjWUtPMjMiLCJzdWIiOiJrbFFlNjhWSGxpZ1kzVDA2R1VZYm5YY1lLTzIzIiwiaWF0IjoxNzA2NDgyNzYwLCJleHAiOjE3MDY0ODYzNjAsImVtYWlsIjoic3VwcG9ydEBub3ZlbGFwcHJvYWNoZXMubmwiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJhcHBsZS5jb20iOlsiMDAxMDg1LjJlNTgwMjk5YmFjNTQ4OWY5ZGVhMzI2Y2M0MzQxYTJmLjIxNTYiXSwiZW1haWwiOlsic3VwcG9ydEBub3ZlbGFwcHJvYWNoZXMubmwiXX0sInNpZ25faW5fcHJvdmlkZXIiOiJhcHBsZS5jb20ifX0.M8kH62RQQY2SWOqdxTOj4TFfFULORVVs3J03HIvNNN37ZADAYt7biLilwpbZ7x6a3HT4VwDwgocFo5MjW5FO8yRnMjjLAOQYPxb1_AloWxUwwa9SDia17ewfIjg_DDsI9PnirqhhxuIwZZCc3ETaoqJwkllAHro68xfVyBrDTNQ6uRR0L9pNAbOkAvzsCVPO9tzRrxWeQYrUaxINusdtOFg8Rbw9NkL9hNStyjLJwSvbBQDYHefEl9U9yId4wIPmoLiJ5C0DNDnuT2Ljt8IwAXEq9zTTvL1yNVp8AuwLKBwBoybzu_NIrEnbZajtYcC5DnD8wFA88p9kyKVp-J4ohA","expirationTime":1706486360125},"createdAt":"1706279622960","lastLoginAt":"1706482760109","apiKey":"APIKEY","appName":"[DEFAULT]"},"providerId":"apple.com","_tokenResponse":{"federatedId":"apple.com/001085.2e580299bac5489f9dea326cc4341a2f.2156","providerId":"apple.com","email":"email@email.com","emailVerified":true,"localId":"klQe68VHligY3T06GUYbnXcYKO23","idToken":"eyJhbGciOiJSUzI1NiIsImtpZCI6IjY5NjI5NzU5NmJiNWQ4N2NjOTc2Y2E2YmY0Mzc3NGE3YWE5OTMxMjkiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vbmEtYWlhbWEiLCJhdWQiOiJuYS1haWFtYSIsImF1dGhfdGltZSI6MTcwNjQ4Mjc2MCwidXNlcl9pZCI6ImtsUWU2OFZIbGlnWTNUMDZHVVliblhjWUtPMjMiLCJzdWIiOiJrbFFlNjhWSGxpZ1kzVDA2R1VZYm5YY1lLTzIzIiwiaWF0IjoxNzA2NDgyNzYwLCJleHAiOjE3MDY0ODYzNjAsImVtYWlsIjoic3VwcG9ydEBub3ZlbGFwcHJvYWNoZXMubmwiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJhcHBsZS5jb20iOlsiMDAxMDg1LjJlNTgwMjk5YmFjNTQ4OWY5ZGVhMzI2Y2M0MzQxYTJmLjIxNTYiXSwiZW1haWwiOlsic3VwcG9ydEBub3ZlbGFwcHJvYWNoZXMubmwiXX0sInNpZ25faW5fcHJvdmlkZXIiOiJhcHBsZS5jb20ifX0.M8kH62RQQY2SWOqdxTOj4TFfFULORVVs3J03HIvNNN37ZADAYt7biLilwpbZ7x6a3HT4VwDwgocFo5MjW5FO8yRnMjjLAOQYPxb1_AloWxUwwa9SDia17ewfIjg_DDsI9PnirqhhxuIwZZCc3ETaoqJwkllAHro68xfVyBrDTNQ6uRR0L9pNAbOkAvzsCVPO9tzRrxWeQYrUaxINusdtOFg8Rbw9NkL9hNStyjLJwSvbBQDYHefEl9U9yId4wIPmoLiJ5C0DNDnuT2Ljt8IwAXEq9zTTvL1yNVp8AuwLKBwBoybzu_NIrEnbZajtYcC5DnD8wFA88p9kyKVp-J4ohA","refreshToken":"AMf-vBybz5V8HnHGFxHoX2ZBRMbxM06QcCXfOVB1HQYtlBlrvnLKcma7G84OkaZXt5zaBJ3XrEwhMxJmrjQnqJTmSvWRk4Gfh9AsubOh8gwhjkc5mcsWkoVaxrVMmtB4XQ07cMud9kb7ytV03sicwu0kDH7UcF8YdjOw348EfaVr5krxoj7Pq5bWUW_3UgY1A2aVuo3GsyqOlj6OcP6WHRaMKBVvYJfshw4H0HZ1sVKjHDp4CI3YaUHaZFzez2LTu2ERuvN7gRpn074wsDV4teeKB-R4uQmUmg","expiresIn":"3600","oauthIdToken":"eyJraWQiOiJsVkhkT3g4bHRSIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoibmwubm92ZWxhcHByb2FjaGVzLmFpYW1hIiwiZXhwIjoxNzA2NTY5MTU5LCJpYXQiOjE3MDY0ODI3NTksInN1YiI6IjAwMTA4NS4yZTU4MDI5OWJhYzU0ODlmOWRlYTMyNmNjNDM0MWEyZi4yMTU2Iiwibm9uY2UiOiI2YjkwZjdjMTFjZTlkMGI3OGJlZDNlODc5ZTQ5NGM4MDRkNWY0Y2NjMmFlYmNhZjI3OTFmMGMyNjY2NDcyZTIyIiwiY19oYXNoIjoid0RBVDl4TklXbEo4V3JoRldkbFdpdyIsImVtYWlsIjoic3VwcG9ydEBub3ZlbGFwcHJvYWNoZXMubmwiLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJhdXRoX3RpbWUiOjE3MDY0ODI3NTksIm5vbmNlX3N1cHBvcnRlZCI6dHJ1ZX0.bE1c7kVYLyA1fZaLXNIv_E701fZaM8EqvB_xoJwJzd8tZfvYlxVqu5bC_ZfWkfv1UUbQrmXyZCgz

⚡️ [log] - Navigating to home
`

Capacitor doctor

Latest Dependencies:

@capacitor/cli: 5.6.0
@capacitor/core: 5.6.0
@capacitor/android: 5.6.0
@capacitor/ios: 5.6.0

Installed Dependencies:

@capacitor/cli: 5.6.0
@capacitor/core: 5.6.0
@capacitor/android: 5.6.0
@capacitor/ios: 5.6.0

[success] iOS looking great! 👌

Before submitting

  • I have read and followed the bug report guidelines.
  • I have attached links to possibly related issues and discussions.
  • I understand that incomplete issues (e.g. without reproduction) are closed.

authStateChange isn't triggered.

I can't find the listener in your code.

This issue has been labeled as needs: reproduction. This label is added to issues that need a code reproduction.

Please provide a Minimal, Reproducible Example using this template in a public GitHub repository so we can debug the issue.

If you have already provided a code snippet and are seeing this message, it is likely that the code snippet was not enough for us to reproduce the issue.

In the constructor of the authentication service, I've the following listener.

       FirebaseAuthentication.removeAllListeners().then(() => {
            FirebaseAuthentication.addListener('authStateChange', (change) => {
                console.log('authStateChange: ', change);
                this.ngZone.run(() => {
                    this.currentUserSubject.next(change.user);
                });
            });
        }).catch((error) => { });

And in ngOnInit() of the login component

      setTimeout(() => {
            this.auth.getRedirectResult().then((result) => {
                this.debugService.log('getRedirectResult() result: ', result);
            }).catch(async (error) => {
                this.debugService.error('getRedirectResult() Error: ', error);

                // Specific error messages, first the generic one
                let alertMessage = 'An error occurred while trying to log you in. Please try again.';
                if (error.code === 'auth/web-storage-unsupported') {
                    alertMessage = 'This browser (or its configuration) is not supported. This usually happens when 3rd party cookies are not enabled in the privacy settings of your browser.';
                }
                const alert = await this.alertController.create({
                    header: 'Authentication Error',
                    message: alertMessage,
                    buttons: ['OK'],
                });

                await alert.present();
            });
        }, 100);

I'm troubleshooting it further today, one thing i noticed was that signInWithCredential() can break quietly if API restrictions are set in the console (such as on referrer), and it won't log in the console (or break the code) unless you explicitly catch the message. Making the API key less strict temporarily didn't resolve the issue.

If you use skipNativeAuth, you will not be logged in on the native layer and cannot use FirebaseAuthentication.addListener('authStateChange', ...) . Use the Firebase JS SDK for this instead (see onAuthStateChanged).

Thank you for your reply and the pointer in the right direction. I have it working somewhat, but still a few kinks to work out and will reply later...one thing that might be unknown is that User objects aren't exactly compatible. for example photoUrl and photoURL and the metadata timestamps, but the following seems to work out (somewhat) still needs more testing.

        const auth = getAuth();
        auth.onAuthStateChanged((user) => {
            if (user) {
                console.log('User is signed in: ', user);
                const tempUser = {
                    displayName: user.displayName,
                    email: user.email,
                    emailVerified: user.emailVerified,
                    isAnonymous: user.isAnonymous,
                    metadata: {
                        creationTime: Number(user.metadata.creationTime),
                        lastSignInTime: Number(user.metadata.lastSignInTime),
                    },
                    phoneNumber: user.phoneNumber,
                    photoUrl: user.photoURL,
                    providerData: [{
                        displayName: user.providerData[0]!.displayName,
                        email: user.providerData[0]!.email,
                        phoneNumber: user.providerData[0]!.phoneNumber,
                        photoUrl: user.providerData[0]!.photoURL,
                        providerId: user.providerData[0]!.providerId,
                        uid: user.providerData[0]!.uid,
                    }],
                    providerId: user.providerId,
                    refreshToken: user.refreshToken,
                    tenantId: user.tenantId,
                    uid: user.uid,
                }

                // this.ngZone.run(() => {
                this.currentUserSubject.next(tempUser);
                // });

            }
        })

I will close this issue since the original problem is resolved.

Thank you, to be clear to others, it wasn't a bug with this plug-in...perhaps the only suggestion would be a comment in the documentation with the listeners that if skipNativeAuth: true is set, that another listener is required.