expo: AuthSession returns dismiss result even before the browser is opened
š Bug Report
Calling the AuthSession.startAsync for the first time returns the dismiss result immediately after calling. The browser opens correctly in the meantime, but any action done afterwards in the browser is ignored (login correctly, cancel, etc). This means that our users will go to the login screen, login successfully, but the app would understand this session as being dismissed.
In addition, but not connected to this issue directly:
- On Android, when the user cancels the login (does not open browser, clicks on
Xin browser, etc) the result sent back to us is alsodismissas well. This means we can not distinguish between cancel and dismiss, which prevents us to create at least a meaningful workaround for this issue. - Calling
AuthSession.dismissbefore starting the session crashes the app (in the Expo client)
Environment
IMPORTANT:
- only happens on Android
- only happens in production mode or the built standalone app (not reproducible in the dev mode)
- only happens on the first call to the
AuthSession.startAsync, successive calls bring the expected behaviour - confirmed in both simulator and Android device
Expo CLI 3.11.3 environment info:
System:
OS: Linux 5.0 Ubuntu 18.04.3 LTS (Bionic Beaver)
Shell: 4.4.20 - /bin/bash
Binaries:
Node: 10.18.0 - /usr/bin/node
npm: 6.13.4 - /usr/bin/npm
npmPackages:
@types/react: ~16.9.0 => 16.9.16
@types/react-native: ~0.60.23 => 0.60.25
@types/react-navigation: ^3.0.7 => 3.0.7
expo: ^36.0.2 => 36.0.2
react: ~16.9.0 => 16.9.0
react-native: https://github.com/expo/react-native/archive/sdk-36.0.0.tar.gz => 0.61.4
react-navigation: ^3.13.0 => 3.13.0
npmGlobalPackages:
expo-cli: 3.11.3
Steps to Reproduce
Simply call AuthSession.startAsync for the first time since the app has been loaded.
Expected Behavior
I would expect that dismissed is not the result, especially that the browser get open and user not knowing what s going proceeds to the login page.
Reproducible Demo
Here is the most simple demo: https://snack.expo.io/rJZ!LryxI
However this needs to be run in the production mode in order to actually get the bug. I am not sure if expo snack supports production mode.
Extra
- I am also linking here a question from StackOverflow from another user having the same issue: https://stackoverflow.com/questions/59589158/expo-authsession-immediately-resolves-as-dismissed
- I guess this can be connected to https://github.com/expo/expo/issues/6289
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 18
- Comments: 53 (15 by maintainers)
Links to this issue
Commits related to this issue
- [android][web-browser] Fix WebBrowser sending 'dismiss' before opening Fixes https://github.com/expo/expo/issues/6679 TL;DR A wrong usage of AppState causes WebBrowser to resolve with `{ type: 'dism... — committed to LucaColonnello/expo by LucaColonnello 4 years ago
- [android][web-browser] Fix WebBrowser sending 'dismiss' before opening Fixes https://github.com/expo/expo/issues/6679 TL;DR A wrong usage of AppState causes WebBrowser to resolve with `{ type: 'dism... — committed to LucaColonnello/expo by LucaColonnello 4 years ago
- [android][web-browser] Fix WebBrowser sending 'dismiss' before opening Fixes https://github.com/expo/expo/issues/6679 TL;DR A wrong usage of AppState causes WebBrowser to resolve with `{ type: 'dism... — committed to LucaColonnello/expo by LucaColonnello 4 years ago
- [android][web-browser] Fix WebBrowser sending 'dismiss' before opening (#6743) * [android][web-browser] Fix WebBrowser sending 'dismiss' before opening Fixes https://github.com/expo/expo/issues/66... — committed to expo/expo by LucaColonnello 4 years ago
- [android][web-browser] Fix WebBrowser sending 'dismiss' before opening (#6743) * [android][web-browser] Fix WebBrowser sending 'dismiss' before opening Fixes https://github.com/expo/expo/issues/6679... — committed to expo/expo by LucaColonnello 4 years ago
Iāve been debugging this and I think I tracked down the issue here.
The problem
In Android and iOS < 11, expo-web-browser used by AuthSession, is using a polyfill version of the NativeAuthSession behaviour available in iOS >= 11.
The way this works is by creating a race condition waiting for one of the following to happen first:
When everything is ok, 2 should happen before 1 and that will dismiss altogether the race condition, resulting in
{ type: 'success' }.What happens here is that the first promise in the race condition throws before opening the browser. The reason is that AppState triggers a
changeevent with stateactivebefore the browser activity is opened, which means that the change event is triggered without a real AppState change.This behaviour is actually by design when no other listener to LifecycleEvent has ever been created, as the initial state will be null before AppState grabs it from the bridge (you can verify this by adding another usage of AppState in your app before calling AuthSession features).
The first listener to a LifecycleEvent gets called as soon as itās added even if state hasnāt changed, to notify of the initial value (this behaviour is also described here https://facebook.github.io/react-native/docs/appstate#basic-usage).
Demo
Hereās a Snack to demonstrate what Iām saying https://snack.expo.io/H1W9Lllg8ā¦
By calling AppState in the render here, Iām triggering AppState to listen for changes earlier, without suffering from the first call handler call (although as said above is not something we can see in Expo Snack, but I used this to solve the same issue in my app and it works consistently everywhere)ā¦
Solution
I have no idea whether this is something that should be taken with ReactNative to argue the design choice of AppState, but the solution for Expo could be to change this https://github.com/expo/expo/blob/master/packages/expo-web-browser/src/WebBrowser.ts#L134-L142 in the following way:
Please let me know if this is ok, I could make a PR or we could discuss furtherā¦
References
anyone in full 2022?
Not sure why this closed, I still experience the issue in production.
Iām experiencing this same problem when using
WebBrowser. openAuthSessionAsync. Everything works in dev mode and in the production iOS app, but fails in the production Android app. Through logging I can see that{ type: 'dismiss' }is returned before the browser even shows, just as described here. The suggested workaround of loggingAppState.currentStateunfortunately seems to no longer work. Iām really at a loss as to where to go from here - I canāt release our app without authentication on Android š@brentvatne @ivansenic Even if there is no solution to this could we at least get this issue reopened as it is linked to in a few other issues? Over half the discussion has been after this issue was closed.
My kudos to @LucaColonnello, I rarely stabmle to such a quick and effective reaction on the bug ticket⦠Workaround provided, fix provided, what can you expect more š P.S. If you ever come to Belgrade I am taking you out for a drink, just ping me š»
@schellack so if you confirm the patch I suggested works, Iām going to open a PR contributing here š
Iām having an issue with
AuthSessionas well, but withuseAuthRequest. I described it on the Expo forum but mentioning it here in case anyone has any ideas. I tried theAppState.currentStateātrickā but that didnāt work for me.Hi @simplesthing ,
I was encountering the same issue as you on Android.
Using
AuthSession.startAsync(), the result of this function always returned{ type: 'dismiss" }even after successful authentication. I was able to get this fixed by supplying areturnUrlto the config object parameter passed toAuthSession.startAsync(). TheAuthSession.startAsync()object parameters are outlined here.It is strange but explicity supplying a
returnUrlparameter, perhaps with a value ofAuthSession.makeRedirectUri(), did the trick for me.@LucaColonnello Thanks so much for your work on this. I have a question. Do you need to do anything other than update the contents of
node_modules/expo-web-browser/src/WebBrowser.tsand republish the app? I still seem to have the double login issue on Android after doing this.yes, I tried it with your changes.
@knorsen Yes, I was able to get it working. Iām using Expo 45 and expo-auth-session. Go checkout the answer from @XiangZhang0216 on this thread https://github.com/expo/expo/issues/10860. His suggested configurations in app.json did the trick.
Does it work with Google-auth ? I followed this step
This works fine on iOS standalone app but on Android every authentication attempt returns dismiss.
Can you share the example code ?
@tajetaje I upgraded to Expo SDK 45 and am still having issues with the standalone Android app. š¦
This is actually my issue: WebBrowser.openAuthSessionAsync returns ādismissā even when the user successfully logged in #6289
On the Android standalone app, the login seems to work, but when coming back to the app it is returning with {type: ādismissā}. It works perfectly on iOS and in the emulator but not on the Android standalone app.
@viantirreau Great, thanks for sharing your solution. Iām not working on this part of the application at the moment but will remind myself to let it know here whether the solution works for me.
@YoranBrondsema I finally solved it using
AuthSession.startAsync! I had to adapt this older Snack, but in the end it just worked fine for my purposes (OAuth). Just make sure to setup theREDIRECT_URLto something on the lines ofhttps://auth.expo.io/@<username>/<app-name>. Although itās more involved, as you have to manually configure some of the urls, I think you can make it work on itsmeās OIDC using this method.Good luck!
@JuanDavidLopez95 Thank you for your response, I have read that issue as well, I am confused as to what the
./helpersfile links to and what thegetAuthorizeUrlis doing, I have searched for this in documentation I do not find anything. I am supplying a redirect uri and everything logs correctly.my code :
my url
loginServiceUrl:https://${Domain}/login?client_id=xxx&redirect_uri=xxx&response_type=code&scope=xxx&state=xxx,`EDITED: Finally got this resolved, a few things,
one I had the incorrect parameter, was using
redirectUriinstead ofreturnUrlusing any type of expo method to ācreate a linkā like
makeRedirectUriorLink.makeUrlall failed, manually typing in strings for the urlās workedmy url
loginServiceUrl:https://${Domain}/login?client_id=xxx&redirect_uri=xxx&response_type=code&scope=xxx&state=xxx&return_url=xxx`This same issue has been plaguing me for months now, but I had not yet been able to get to root cause. I used the patch to Expo WebBrowser that @LucaColonnello posted above, tested it in my app, and it seems to work perfectly.