AFAuth signInAnonymously not working properly without page refresh
Version info
Angular: Angular CLI: 15.1.6 Node: 16.15.1 Package Manager: npm 9.2.0 OS: win32 x64
Angular: 15.2.8 ... animations, cdk, common, compiler, compiler-cli, core, forms ... material, platform-browser, platform-browser-dynamic, router
Package Version
@angular-devkit/architect 0.1502.7 @angular-devkit/build-angular 15.2.7 @angular-devkit/core 15.2.7 @angular-devkit/schematics 15.1.6 @angular/cli 15.1.6 @angular/fire 7.5.0 @schematics/angular 15.1.6 rxjs 7.8.1 typescript 4.9.5
Firebase:
9.21.0
AngularFire:
7.5.0
Other (e.g. Ionic/Cordova, Node, browser, operating system):
How to reproduce these conditions
Failing test unit, Stackblitz demonstrating the problem I'm working on this now
Steps to set up and reproduce See notes. This project is deployed on firebase
Sample data and security rules
Use the deployed website
Debug output
See notes below
** Screenshots **
Here's a video showing the described behavior
https://www.awesomescreenshot.com/video/17419987?key=8bec7baa19f0d455d9b572eb1949f269
Expected behavior
See notes below
Actual behavior
See notes below
NOTES:
I'm having an issue with AngularFireAuth anonymous sign in. After logging in, the app works fine the first time, but if I log out and log back in as a different anonymous user, the app doesn’t work as intended. A page refresh is needed to restore the correct app functionality. The attached video shows this behavior. Note that I'm using the Auth emulator for this, but the same behavior is observed in my deployed site (see below)
I’m trying to figure out how to do a Stackblitz for this but I didn’t want to wait until that’s done until I brought this up. Right now I’m wondering if there’s anything you can see here that might indicate a cause.
This site is deployed on firebase, so you can see this behavior for yourself at www.robertrinehart.com.
Go to www.robertrinehart.com/kanban/login and follow the user flow I describe below to see the bug in action. You’ll be able to sign in anonymously and also log in using an email address (not verifying now), google, github etc. so you can see it only happens with anonymous sign in. In the BoardView sidenav I added an ‘Add Sample Board’ button that you can click once to instantly create a board.
Description:
I’m using NgRx component store for state management and I’m signing in to my app using the AngularFireAuth signInAnonymously method. Once in the app (in ‘Board View’) I then create a 'board' object that is saved to firestore. This works fine the first time. You can create as many boards as desired no problem.
However, if I then log out and log back in as a different anonymous user, then create a board in the same way, the board is created, but the board is not shown in the list of boards in the left sidenav. After a board is created I expect it to appear in this list and the number of boards value to be updated.
I’m using the ComponentStore effect to create a board, then in that effect, after the board is created, I call another effect to fetch all the boards for the logged in user.
App.module.ts imports
import { connectFirestoreEmulator, getFirestore, provideFirestore, enableMultiTabIndexedDbPersistence } from '@angular/fire/firestore';
import { getAuth, provideAuth } from '@angular/fire/auth';
import { initializeApp, provideFirebaseApp } from '@angular/fire/app';
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideAuth(() => {
const auth = getAuth();
if (environment.useEmulators) {
connectAuthEmulator(auth, 'http://localhost:9099', {disableWarnings: false});
}
return auth;
}),
provideFirestore(() => {
const firestore = getFirestore();
if (environment.useEmulators) {
connectFirestoreEmulator(firestore, 'localhost', 8080);
}
return firestore;
}),
SignInAnonymously
import { Auth, User, user, onAuthStateChanged, signInAnonymously } from '@angular/fire/auth';
constructor(private auth: Auth, readonly router: Router) {}
signInAnonymously() {
signInAnonymously(this.auth)
.then(() => {
// console.log('lR sIA anon login success. nav to /kanban/board');
this.router.navigateByUrl(AppRoutes.KANBAN_BOARD);
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.log('lR sIA anon login error code/message: ', errorCode, errorMessage);
});
}
ComponentStore CreateBoard effect:
readonly createBoard = this.effect((board$: Observable<Board>) => {
return board$.pipe(
concatMap(board => this.boardsService.createBoard(board).pipe(
tap((board) => {
console.log('bSt cB created board: ', board);
if (board.ownerUid) {
console.log('bSt cB call get boards for user: ', board.ownerUid);
this.getAllBoardsForUser(board.ownerUid); // this is the effect that is bypassed
console.log('bSt cB after get boards call');
}
this.setSelectedBoard(board);
}),
catchError(error => {
console.log('bSt gB error: ', error);
return of(error);
})
))
)
});
Get all boards for user effect:
readonly getAllBoardsForUser = this.effect<string>((userId$: Observable<string>) => {
return userId$.pipe(
switchMap((userId) => {
console.log('bSt gABFU getting boards for user: ', userId);
return this.boardsService.listBoardsForUser(userId).pipe(
tap(( boards) => {
// firebase returns a DocumentData[] so need to cast as Board[]
const bds = boards as Board[];
this.setBoards([...bds])
console.log('bSt gABFU boards from backend: ', boards);
}))}
))
});
ListBoardsForUser firestore service method
listBoardsForUser(userId: string): Observable<DocumentData[]> {
console.log('bSvc lBFU list boards for user: ', userId);
const boards = collection(this.db, BOARDS_COLLECTION);
const q = query(boards, where('ownerUid', '==', userId));
return collectionData(q);
}
In debugging, I can see that after creating the board, for some reason the code execution bypasses the call to the component store effect to fetch all the boards for the user and the UI is not updated.
First anonymous user normal logs:
bSt cB created board: {displayName: 'xxcvbxcvbxcvbcxb', description: '', ownerUid: 'mzj8tXF38fYjtplwXox6xyuDcch0', id: '6ORqaFDHdynEn39i77b7'}
bSt cB call get boards for user: mzj8tXF38fYjtplwXox6xyuDcch0
bSt gABFU getting boards for user: mzj8tXF38fYjtplwXox6xyuDcch0 // this is skipped when erroring
bSvc lBFU list boards for user: mzj8tXF38fYjtplwXox6xyuDcch0
bSt cB after get boards call
bSt gABFU boards from backend: [{…}]
Second anonymous user fail logs:
bSt cB created board: {displayName: 'cvbncvbncvbnvbn', description: '', ownerUid: 'eP2wMocf6yuoD50YpU3k3d1DQnY7', id: '43fqVLwYzpTI0HEkCG0s'}
bSt cB call get boards for user: eP2wMocf6yuoD50YpU3k3d1DQnY7
// getAllBoardsForUser effect should run here
// listBoardsForUser service method should run here
bSt cB after get boards call
This is the problem. For some reason, the effect that retrieves the list of boards from the backend for this anonymous user just does not fire. It gets bypassed. At this point you can create boards and persist them in the backend, but the UI is never updated so the boards you create don’t show up in the list in the sidenav and the number of boards is not updated. However, each board you create is set as the ‘Selected Board’ and its title shows up in the header. I have no idea why the effect would not fire.
You can see in the console logs where the getAllBoardsForUser effect is invoked when logged in anonymously the first time, but the with the second anon user the effect simply doesn't run (I hover the cursor over these lines in the video several times). The code execution just skips the effect.
To get the new board and the list of boards to show in the UI it is necessary to reload the page. When you do that, all the boards you've created that weren't previously shown and number of boards value are correctly shown (you can see this in the video). At this point the app works correctly and you can create as many boards as you want.
Observations: This behavior doesn't happen if you reload the login page each time you return to it. It only happens when the login page isn't reloaded. I suspect the issue is here, but I can’t isolate the cause.
Also, this only happens when using sign in anonymously. If I use login with google, github, etc. or email login it doesn't happen at all.
User Flow In the video you can see the flow
- Click the ‘Sign in as guest’ button to log in as an anonymous user
- Click the Create a board button and give it a name and save it. This sends the board to firestore.
- The board is shown in the left sidenav and the number of boards is updated. You can see in the console where the method to fetch the boards is run (the line bSvc lBFU list boards for user is the call to firestore to fetch the boards).
- Click the Log out option in the three dots menu in the upper right and return to the login page. Don't refresh the login page.
- Log in again as a different anonymous user
- Create a board
- The board title does not appear in the list of boards in the sidenav and the number of boards is not updated.
- Refresh the page
- The previously created boards that didn't appear in the UI are now shown and the number of boards value is correctly updated
After you create a board, you can see in the console that the board is created, but just after this, the effect to fetch all the boards for this user is skipped. You can see in the console where the effect should execute, but it just doesn't run. There's no line in the log where the call to firestore should be made.
At the end of the video I did a few cases where I refresh the login page each time I return to it. In this case, after logging in as a different user, I'm able to create a board each time and the call to fetch boards for the user is executed each time. This only happens when you refresh the login page each time you return to it. If you don't refresh the login page before you sign in anonymously, the call to fetch the boards for the user is bypassed until you refresh the page in the board view.
Also, this behavior doesn’t occur at all when logging in using any other method than sign in anonymously, whether or not you refresh the login page or Board view (not shown in video).
Hopefully this makes sense. If you have any questions please LMK. I hope it's not something silly I've been stuck for days. I'll add a comment if I'm able to get a stackblitz to reproduce the error. Any ideas are greatly appreciated! Thanks for your help! Robert
Anyone? This is a good one! :)
Hi Is there anyone that can take a look at this? Thanks