opened
ir-fuel
username_0
<!-- DO NOT DELETE
validate_template=true
template_path=.github/ISSUE_TEMPLATE/bug_report.md
-->
### [REQUIRED] Step 1: Describe your environment

  * Xcode version: 12.4
  * Firebase SDK version: 7.6.0
  * Installation method: ` Swift Package Manager`
  * Firebase Component: Auth

### [REQUIRED] Step 2: Describe the problem

When starting an app that hasn't been started in a while (several days), and where the user has been deleted server side (either by deleting on the server or just having killed the local simulator), the `addStateDidChangeListener` callback is called multiple times at app startup. The first time it contains the user object that was previously valid but which has been removed server-side since, and the second time it contains `nil` as to show there is no active user.

As there is no way to see on the `user` object if it is a "good" one I don't see how I can know if we are actually logged in and good to go, or just temporarily get something back and will receive a `nil` very soon after. This is problematic for building the interface of the app as the screens depend on if we have a user or not.

#### Steps to reproduce:

Create a Firebase user in your app. 
Kill your app.
Delete the created user from Firebase (or just kill the simulator if running locally)
Wait a few days
Start the app again

#### Relevant Code:

```
        listenerHandle = Auth.auth().addStateDidChangeListener { [weak self] _, user in
            if let self = self {
                
                if user != nil {
                    debugPrint("Has authenticated user")
                } else {
                    debugPrint("Does not have authenticated user")
                }
                
                self.user = user
                
                self.hasAuthenticatedUser = user != nil
            }
        }

```


So the question is: is this behavior normal, and if it is, how can I be sure that the user object I get is an authenticated user?
addStateDidChangeListener called multiple times when user does no longer exist at app startup
issue
created
morganchen12
username_1
From what I understand this is correct behavior from the SDK. If you want to ensure your user is valid, you can try to [reload](https://firebase.google.com/docs/reference/ios/firebaseauth/api/reference/Classes/FIRUser#/c:objc(cs)FIRUser(im)reloadWithCompletion:) the user before performing any operations.

@username_2 please correct me if I am wrong.
comment
created
ir-fuel
username_0
I did some more testing. This is my test code

```
        listenerHandle = Auth.auth().addStateDidChangeListener { _, user in
            if user != nil {
                debugPrint("Received a user, let's see if it is still valid")
                user!.reload { error in
                    if error != nil {
                        user!.getIDToken { _, error in
                            if error != nil {
                                user!.logout()
                                debugPrint("User no longer valid")
                                Self.userPublisher.value = nil
                            } else {
                                debugPrint("Has authenticated user after get ID token")
                                Self.userPublisher.value = user
                            }
                        }
                    } else {
                        debugPrint("Has authenticated user")
                        Self.userPublisher.value = user
                    }
                }
            } else {
                debugPrint("Received nil user")
                Self.userPublisher.value = nil
            }
        }
```

I ran this code after killing the local Firebase emulator, so the user no longer exists. this is what it logged:
```
"Received a user, let\'s see if it is still valid"
"Received nil user"
"Has authenticated user after get ID token"
```

So what happens is there is a user object passed, I call `reload` on that user to see if it is still valid, there is no error after the reload so I call `getIDToken`, in the mean time the callback is called again with an empty user, and the `getIDToken` returns me a valid token, which in the mean time has become invalid.

So again: no way for me to be sure I have a valid user.

Is this normal?
comment
created
ir-fuel
username_0
Just tried it again.:

- start emulator
- create account in app
- kill emulator
- restart emulator
- restart app

result:

"Received a user, let\'s see if it is still valid"

 [Firebase/Auth][I-AUT000016] Invalid user token detected, user is automatically signed out.

"Received nil user"

"Has authenticated user after get ID token"


So it did it again.
comment
created
morganchen12
username_1
@username_2 is this a bug?
comment
created
rosalyntan
username_2
Hi @username_0 -- this looks WAI to me. The docs state that the [`addStateDidChangeListener` will be triggered immediately when the block is registered as a listener](https://firebase.google.com/docs/reference/swift/firebaseauth/api/reference/Classes/Auth#addstatedidchangelistener_:), so it triggers with the cached user at app startup.

As @username_1 said, you can check whether the user is valid by calling `reload`. You mention that `reload` doesn't return an error, but from your logged debug statements, it looks like it does (since you call `getIDToken` only if `reload` returns an error).
comment
closed
rosalyntan
username_2
issue
created
ir-fuel
username_0
Sorry @username_2  but this is not correct. I would like to reopen this :) 
As you can see in the logs, reload does not return an error, nor does `getIDToken`. The listener is called a second time when the async callbacks fired during the first call are still running.
What happens is:

- Listener callback is called
- I get user
- I call `reload` on that user
- Listener callback is called AGAIN with nil user (but the `reload` callback on the first user I got is still pending)
- The first user I received reloads without errors and I call `getIDToken`.
- `getIDToken` returns without an error making me think I have a valid user.

This is weird behaviour and does not allow me to detect if a user is still valid at startup
comment
created
ir-fuel
username_0
Ah yes, it's a typo. Oh boy ...
comment