Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auth does not work in ionic apps on iphone devices or sims #2979

Closed
donhmorris opened this issue Sep 23, 2021 · 28 comments
Closed

Auth does not work in ionic apps on iphone devices or sims #2979

donhmorris opened this issue Sep 23, 2021 · 28 comments

Comments

@donhmorris
Copy link

donhmorris commented Sep 23, 2021

Version info

Angular 12.1.1

Firebase 9

@angular/fire 7.0.4

ionic 5.5.2

How to reproduce these conditions

Create a sign in with email and password login. Will work in browser; will not work in iphone simulator or iphone device. It will just hang, waiting for a login result.

Steps to set up and reproduce

  1. clone git clone https://donhmorris@bitbucket.org/donhmorris/testlogin.git
  2. run npm i
  3. run ionic lab
  4. login in browser with credentials: email = 'don@test.com'. pwd = 'password'
  5. Message will be displayed in app that says "Signed in as don@test.com" and Logout button is displayed on success. A toast will appear in red if an error occurs.
  6. stop ionic lab; run ionic cap run ios
  7. select an iphone simulator model. Any version will do. Recommend iphone 13.
  8. attempt to login using the previous credentials
  9. nothing will happen. no errors, exceptions or anything. app just hangs

Notes
A firebase project is setup to specifically test the supplied demo app.

Debug output

** Errors in the JavaScript console **
None
** Output from firebase.database().enableLogging(true); **

** Screenshots **

Expected behavior

Login is successful and a message is displayed showing the email used to sign in.

Actual behavior

App hangs with no error messages

@j0s3v4rg4s
Copy link

I found that the login function is working, the problem is on change detection of this.auth.onAuthStateChanged for any strange reason it don't update the user state

@donhmorris
Copy link
Author

donhmorris commented Sep 25, 2021 via email

@playaz87
Copy link

playaz87 commented Sep 27, 2021

Also experiencing this. authstate.subscribe() is not firing when the auth state changes. Anyone found a solution yet?

Downgrading to @angular/fire": "^6.0.4" and "firebase": "^8.0.1" works.

@donhmorris
Copy link
Author

I also found downgrading @angular/fire works as well as using Firebase sdk v8. Looks like this was broken in Firebase sdk 9.

@jamesdaniels
Copy link
Member

Going to close as this isn't an issue with AngularFire, please open over on the JS SDK repo.

@NLueg
Copy link

NLueg commented Oct 12, 2021

If anyone also has this issue, I solved it as suggested in the issue firebase/firebase-js-sdk#5019 with this code:

import {
  getAuth,
  indexedDBLocalPersistence,
  initializeAuth,
  provideAuth,
} from '@angular/fire/auth';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    ...
    provideAuth(() => {
      if (Capacitor.isNativePlatform()) {
        return initializeAuth(getApp(), {
          persistence: indexedDBLocalPersistence,
        });
      } else {
        return getAuth();
      }
    }),
  ]
})

@ejirocodes
Copy link

@eeschiavo
Copy link

eeschiavo commented Nov 10, 2021

I've the same problem but solution provided by @ejirocodes doesn't work for me. I'm using AngularFireAuth and AngularFireStorage.

I can confirm downgrading to @angular/fire": "^6.1.5" and "firebase": "^8.10.0" works.

@rodrigoreal
Copy link

rodrigoreal commented Nov 10, 2021

If anyone also has this issue, I solved it as suggested in the issue firebase/firebase-js-sdk#5019 with this code:

import {
  getAuth,
  indexedDBLocalPersistence,
  initializeAuth,
  provideAuth,
} from '@angular/fire/auth';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    ...
    provideAuth(() => {
      if (Capacitor.isNativePlatform()) {
        return initializeAuth(getApp(), {
          persistence: indexedDBLocalPersistence,
        });
      } else {
        return getAuth();
      }
    }),
  ]
})

@NLueg thank you man, saved my day, was struggling here for hours.

@bocodigital
Copy link

Can you share how you handled it in your component?

@donhmorris
Copy link
Author

In your main app component

import { Component } from '@angular/core';
import { Capacitor } from '@capacitor/core';
import { initializeApp } from 'firebase/app';
import { indexedDBLocalPersistence, initializeAuth } from 'firebase/auth';
import { environment } from 'src/environments/environment';

@component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.scss'],
})
export class AppComponent {
constructor() {
const app = initializeApp(environment.firebase);
if (Capacitor.isNativePlatform) {
initializeAuth(app, {
persistence: indexedDBLocalPersistence
});
}
}
}

@bocodigital
Copy link

Im looking at what @rodrigoreal did. Looks like what @donhmorris is saying is to ditch angularfire all together for native. But it looks like @rodrigoreal added that to his appModule but I don't get how that works.

@bocodigital
Copy link

@donhmorris are you removing all the angularfire imports from the appModule?

@donhmorris
Copy link
Author

You can do the same thing with angular fire. Playing bf 2042 right now. I’ll see if I can grab my code for angular fire in a few b

@bocodigital
Copy link

@donhmorris thanks!!

@rodrigoreal
Copy link

rodrigoreal commented Nov 13, 2021

@bocodigital

app.module.ts

import { provideFirebaseApp, getApp, initializeApp } from '@angular/fire/app';
import { provideAuth, getAuth, indexedDBLocalPersistence, initializeAuth } from '@angular/fire/auth';
import { provideStorage, getStorage } from '@angular/fire/storage';
import { provideMessaging, getMessaging } from '@angular/fire/messaging';

imports: [
    provideFirebaseApp(() => initializeApp(environment.firebase)),
    provideAuth(() => {
      if (Capacitor.isNativePlatform()) {
        return initializeAuth(getApp(), {
          persistence: indexedDBLocalPersistence
        });
      } else {
        return getAuth()
      }
    }),
    provideMessaging(() => getMessaging()),
    provideStorage(() => getStorage()),
]

And for exemple in my auth service you need to do something like that:

import { Auth, signInWithEmailAndPassword } from '@angular/fire/auth';
@Injectable({
  providedIn: 'root'
})
export class AuthService {
constructor(
    private afAuth: Auth,
  ){}
  
  signinWithEmailAndPasswordd(email: string, password: string) {
    return signInWithEmailAndPassword(this.afAuth, email, password);
  }
}

@donhmorris
Copy link
Author

@bocodigital I can't find that code. Weird. I know I did it.
What others have shown for angular fire is what I remember I did.

@bocodigital
Copy link

@donhmorris and @rodrigoreal right now my firebsase and firestore services are using compat. Can I mix them?

@rodrigoreal
Copy link

@bocodigital idk man, i dont think so, i was also using compat, but i migrated it to modular when i upgraded to firebase 9 and i only discovered this problem after, so i cant help you to fix that with compat.

@bocodigital
Copy link

@rodrigoreal @donhmorris I got it working with a combo of compat and modular. I will just port the whole thing to modular. I don't see the point of angular fire though since firebase v9 has everything you need.

@eeschiavo
Copy link

I can confirm @rodrigoreal solution is working but the app must use angular fire 7 APIs.

@MaxLeggieri
Copy link

If anyone also has this issue, I solved it as suggested in the issue firebase/firebase-js-sdk#5019 with this code:

import {
  getAuth,
  indexedDBLocalPersistence,
  initializeAuth,
  provideAuth,
} from '@angular/fire/auth';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    ...
    provideAuth(() => {
      if (Capacitor.isNativePlatform()) {
        return initializeAuth(getApp(), {
          persistence: indexedDBLocalPersistence,
        });
      } else {
        return getAuth();
      }
    }),
  ]
})

@NLueg thank you man, saved my day, was struggling here for hours.

This also resolved my issue, still can't found an official bug on this.
The mix between web and native is still blurry on a so popular tool.

@jamesonsaunders
Copy link

The real problem: firebase-js-sdk on mobile iOS assumes google API (gapi) exists on the window, even when it isn't used.

I found a work around: Mock window.gapi before using firebase auth login:

window['gapi'] = {
  load: (name: string) => Promise.resolve(),
  iframes: {
    getContext: () => {
      return {
        iframe: {
          contentWindow: {
            postMessage: (message: any) => {
              console.log("gapi iframe message:", message);
            }
          }
        }
      }
    }
  }
} as any;

@nskoro
Copy link

nskoro commented Sep 5, 2022

using firebase 9.8.4 worked

@SheldonHage
Copy link

@MaxLeggieri I believe I read on the Firebase GitHub that this was expected behavior and your code example is the correct implementation so they chose not to open a bug report. This worked for me as well btw.

@Joep-DDQ
Copy link

the provideAuth() implementation also solved my issue. Can't believe this isn't mentioned in the docs. I wasted weeks on this!

@lukeweston1234
Copy link
Contributor

In case anyone is using Bootstrapped components

In your main.ts

bootstrapApplication(AppComponent, {
  providers: [
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
    provideRouter(routes),
    importProvidersFrom(
      IonicModule.forRoot({}),
      provideFirebaseApp(() => initializeApp(environment.firebase)),
      provideAuth(() => {
        if (Capacitor.isNativePlatform()) {
          return initializeAuth(getApp(), {
            persistence: indexedDBLocalPersistence,
          });
        } else {
          return getAuth();
        }
      }),
      provideFirestore(() => getFirestore()),
      provideStorage(() => getStorage()),
      provideFunctions(() => getFunctions())
    ),
  ],
});

@inertjade
Copy link

@bocodigital

app.module.ts

import { provideFirebaseApp, getApp, initializeApp } from '@angular/fire/app';
import { provideAuth, getAuth, indexedDBLocalPersistence, initializeAuth } from '@angular/fire/auth';
import { provideStorage, getStorage } from '@angular/fire/storage';
import { provideMessaging, getMessaging } from '@angular/fire/messaging';

imports: [
    provideFirebaseApp(() => initializeApp(environment.firebase)),
    provideAuth(() => {
      if (Capacitor.isNativePlatform()) {
        return initializeAuth(getApp(), {
          persistence: indexedDBLocalPersistence
        });
      } else {
        return getAuth()
      }
    }),
    provideMessaging(() => getMessaging()),
    provideStorage(() => getStorage()),
]

And for exemple in my auth service you need to do something like that:

import { Auth, signInWithEmailAndPassword } from '@angular/fire/auth';
@Injectable({
  providedIn: 'root'
})
export class AuthService {
constructor(
    private afAuth: Auth,
  ){}
  
  signinWithEmailAndPasswordd(email: string, password: string) {
    return signInWithEmailAndPassword(this.afAuth, email, password);
  }
}

Thank you so much for posting this. I am now able to get past this blocker.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests