CocoaPodsCan not synchronize the retrieval of an ID token using a DispatchSemaphore.
Calling Firebase.User.getIDToken and awaiting its result using a semaphore results in the closure never getting called.
If the semaphore is given a timeout, the closure completes (almost) immediately after the timeout is over, suggesting that the semaphore is blocking the getIDToken call, too.
I have also tried wrapping the call in a global dispatch queue, with the same result. I have provided the simpler version below.
How can I write the token-retrieving code in a synchronous way?
let semaphore = DispatchSemaphore(value: 0)
var token: String?
Auth.auth().currentUser?.getIDToken { firebaseToken, error in
token = firebaseToken
semaphore.signal()
}
semaphore.wait()
print("Token is \(token)")
I've tracked this as a feature request internally as b/160627142. @rosalyntan may have some ideas why your workaround doesn't work.
I also encountered the same situation, and I want to use the implementation like this in our product.
I'm not sure, but I think that's due to the thread-safety model of Auth. getIDToken, internally getIDTokenWithCompletion pushes the passed completion block to dispatch_main_queue. This causes dead-locking at semaphore.wait() on the main-thread.
ref: https://github.com/firebase/firebase-ios-sdk/blob/master/FirebaseAuth/Docs/threading.md
@musaprg I also noticed the same thing in the source code, that absolutely seems to be the cause of the deadlock.
@rosalyntan can you suggest a workaround to this issue? I understand that this feature request might not be high priority for the Firebase team right now but a temporary solution, if it exists, would be much appreciated. Thanks!
Hi @emilioschepis, thanks for filing this issue! Firebase Auth APIs are asynchronous by design, and blocking the main thread to wait for the completion of getIDToken is not advised. May I ask what you are trying to accomplish by synchronizing the retrieval of the ID token? Can you achieve what you want by putting whatever is waiting for the semaphore into the completion block instead?
Hi @rosalyntan, here is my use case:
I am using the Apollo iOS library to make GraphQL requests to a server, and I send the user's current Firebase JWT token to authenticate.
As you can see from the docs, headers for each request are defined in a delegate method.
Unfortunately this method does not have a completion block; instead it directly changes an inout parameter on the request itself. For this reason, I need to block the thread through a semaphore until the token is available so that I can use it inside the request.
Is there a way to achieve the same result while respecting Firebase Auth's asynchronous approach?
Thanks.
+1 Having the same issue.
@emilioschepis A (terrible) internal workaround (we haven't launched yet) is to save the access token locally per session on login, rather than checking every request - hoping we can find a better approach soon.
@daihovey thanks for the tip. I'm still in the prototyping phase and my backend database (Hasura) supports a combination of admin secret and role so I can simulate being any user I need. As you said, however, these workarounds won't be secure enough for production so let's hope an official fix or workaround will come soon.
@rosalyntan any update you can share regarding this issue?
Most helpful comment
@musaprg I also noticed the same thing in the source code, that absolutely seems to be the cause of the deadlock.
@rosalyntan can you suggest a workaround to this issue? I understand that this feature request might not be high priority for the Firebase team right now but a temporary solution, if it exists, would be much appreciated. Thanks!