Hi everyone!
I put this issue on AngularFire2 GitHub, but people says that is an firebase-js-sdk issue. When I sign in with redirect method, the promise is never reached, but with popup method all is ok.
Any suggestion?
import { Injectable } from '@angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
import * as firebase from 'firebase/app';
import { Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class AuthService {
public user: firebase.User;
public authState$: Observable<firebase.User>;
private authProvider: any;
constructor(private afAuth: AngularFireAuth, private router: Router) {
this.authState$ = afAuth.authState;
this.authState$.subscribe( user => this.user = user );
}
login(provider: number) {
switch (provider) {
case 1: this.authProvider = new firebase.auth.FacebookAuthProvider();
break;
case 2: this.authProvider = new firebase.auth.GoogleAuthProvider();
break;
case 3: this.authProvider = new firebase.auth.TwitterAuthProvider();
break;
case 4: this.authProvider = new firebase.auth.GithubAuthProvider();
}
this.afAuth.auth.signInWithRedirect(this.authProvider)
.then( success => {
this.router.navigate(['dashboard']); // <-- NEVER REACHED
})
.catch( error => console.error('ERROR', error));
}
logout() {
this.afAuth.auth.signOut().then( success => {
this.router.navigate(['login']);
});
}
isLoggedIn(): boolean {
return this.user !== null;
}
}
Hey there! I couldn't figure out what this issue is about, so I've labeled it for a human to triage. Hang tight.
When you call signInWithRedirect, the page should immediately redirect. The promise may not resolve. Even if you try to run some logic there, it is likely to be interrupted due to the page redirect.
If I am at /login, when I complete the signInWithRedirect, I come back to /login and I'm not redirected to /dashboard, like I am trying with this code.
this.afAuth.auth.signInWithRedirect(this.authProvider)
.then( success => this.router.navigate(['dashboard']) );
Sorry for my english 馃槚
Hey @albertososa101,
When you call firebase.auth().signInWithRedirect on /login, you will be redirected to the Auth provider to sign in and then redirected back to /login where the sign in completes. You will detect the result there and redirect to /dashboardby calling firebase.auth().getRedirectResult().
firebase.auth().getRedirectResult().then(result => {
if (result.user) {
// User just returned to `/login` from a successful sign in attempt.
// Navigate to `/dashboard`
}
});
@bojeil-google yea, it works with this code... But I've the same functionallity through AuthGuard. The problem persists: promise returned from signInWithRedirect is never reached.
As I said earlier, signInWithRedirect will redirect to another page before it resolves.
@bojeil-google sorry but I'm lost... I arrive at /login page, then I click on signInWithRedirect button of desired provider to be redirected to the provider login page. After that, I'm redirected back to /login. Now at this point, where I should put your code to be redirected to /dashboard? ngOnInit()? constructor()?
As @bojeil-google commented, you should put the redirect logic inside firebase.auth().getRedirectResult() promisse. I recommend this link https://firebase.google.com/docs/auth/web/google-signin?hl=pt-br
@douglashm yes I know, but firebase.auth().getRedirectResult() should be put into on load page lifecycle. My Auth code is into a service on Angular2.
@albertososa101 your AuthService is a singleton. My guess is, if you do this, should work:
login(provider: number) {
...
this.afAuth.auth.signInWithRedirect(this.authProvider);
this.afAuth.auth.getRedirectResult().then(result => {
if (result.user) {
this.router.navigate(['dashboard']);
});
}
@douglashm it doesn't work. I've already try it. :(
@albertososa101 even though it is declared in the main module?
@douglashm yes of course, the app works well with signInWithPopup(). The throuble is with signInWithRedirect(). I'm lost.
@albertososa101 there was an error in my example code. The code getRedirectResult should be placed in another method, so it can be executed after page reload. I've tested it here successfully.
My environment:
Angular CLI: 1.5.0
Node: 9.1.0
OS: win32 x64
Angular: 4.4.6
login(provider: number) {
this.afAuth.auth.signInWithRedirect(this.authProvider);
}
ngOnInit() {
this.afAuth.auth.getRedirectResult().then(result => {
if (result.user) {
//route
});
}
These kind of questions are better suited for stackoverflow as you also get other angular developers to provide feedback/answers while other developers with similar issues will be able re-use the answers provided.
You can also detect the Auth state in your login page using onAuthStateChanged listener. Typically you should set that up on initialization and redirect the user to the dashboard when you know he/she is already logged in.
Too many Angular developers have the same trouble as me. I think that this is a firebase-js-sdk issue on signInWithRedirect(). If it is a promise, why the promise is never reached? Why signInWithPopup() works fine? I asked in StackOverflow and people suggested me to open an issue here.
Thanks @douglashm and @bojeil-google, both answers worked for me, but it doesn't answer my issue on signInWithRedirect() as a service.
You should not rely on signInWithRedirect resolving so you can run logic, because as I explained earlier, it will be interrupted when the page redirect happens. We could tweak the promise to resolve but in the list of things to do and features that developers need, this is really low. I label it as a p3.
@bojeil-google I'm facing a similar issue in mobile with Service Worker.
When I'm doing signInWithRedirect it's not going to google's auth page itself.
When I'm doing signInWithPopup the app gets close when google's auth is done.
So currently I'm suck here
please help me out
thanks
Please clarify what your issue is, @NikhilTalwar15 . What do you mean "with Service worker"? Firebase Auth library doesn't currently work in a service worker. You need to provide more details that provide us the ability to recreate the issue.
look https://firebase.google.com/docs/auth/web/cordova
there are 2 way
firebase.auth().signInWithRedirect(provider).then(function() {
firebase.auth().getRedirectResult().then(function(result) {
var token = result.credential.accessToken;
var user = result.user;
}).catch(function(error) {
var errorCode = error.code;
var errorMessage = error.message;
});
});
firebase.auth().getRedirectResult().then(function(result) {
if (result.credential) {
var token = result.credential.accessToken;
var user = result.user;
}
}).catch(function(error) {
});
Any updates on this? I have a similar code like @wangta69
return this.afAuth.auth.signInWithRedirect(new firebase.auth.GithubAuthProvider().addScope('repo')).then(() => {
this.afAuth.auth.getRedirectResult().then(res => {
if (res.user) {
this.localStorage.removeItem('token');
this.localStorage.setItem('token', res.credential.accessToken);
}
});
});
and i don't reach the accessToken.
This is based on item 4 from https://firebase.google.com/docs/auth/web/cordova
Step 1. Add a method to the auth service to authorize the redirect. Pass a function to the method that actually handles the redirect.
redirectIfAuthorized( redirectFunc: () => void ){
this.afAuth.auth.getRedirectResult().then( (result) => {
if (result.user) redirectFunc();
});
}
Step 2. Implement the ngOnInit() function in the LoginComponent to supply some redirect logic.
constructor(
private authService: AuthService,
private route: ActivatedRoute,
private router: Router
) { }
// .........
ngOnInit(){
var routeSnapeshot = this.route.snapshot;
this.authService.redirectIfAuthorized(() => {
var returnUrl = routeSnapeshot.queryParamMap.get('returnUrl') || '';
this.router.navigate([returnUrl]);
});
}
There is a problem with this solution though. After signing in, we first go to the login page, hang around there for a noticeable time (typically about a second), and only then do we get redirected to the return URL. It's not a seamless experience. Anyone have any comments on this approach and ways to get rid of this lag?
@popeax i think this is a design decision. Add a loading spinner or something while you are waiting for the response.
@albertososa101 your
AuthServiceis a singleton. My guess is, if you do this, should work:login(provider: number) { ... this.afAuth.auth.signInWithRedirect(this.authProvider); this.afAuth.auth.getRedirectResult().then(result => { if (result.user) { this.router.navigate(['dashboard']); }); }
Thanks...
Closing as obsolete. Please re-open with update repro steps if you're still experiencing this issue!
Even though it's closed, this is a top google result so I will add this here, since it seems to not be clear to many newbies:
When you call signInWithRedirect -> your app is basically unloaded as the user is now on the Firebase auth page (look at the url).
After that it redirects BACK to your application to the same route it was on when you called it (for most people something like /login, /sign-in, /sign-up /register etc).
So there is no point in trying to run code immediately AFTER calling signInWithRedirect, as that code is unreachable. This is why there is the method getRedirectResult - which should be somewhere in your startup routine.
Since your app was unloaded, it now starts up again FROM NEW and returns to that same route it was on before you called signInWithRedirect. Obviously that is not the route a user would expect after having clicked a button to login/register. So you need to put some logic in your startup code to handle that (eg show a spinner and once you get the result in getRedirectResult navigate to /home or wherever)
Most helpful comment
Hey @albertososa101,
When you call
firebase.auth().signInWithRedirecton/login, you will be redirected to the Auth provider to sign in and then redirected back to/loginwhere the sign in completes. You will detect the result there and redirect to/dashboardby callingfirebase.auth().getRedirectResult().