expo: Auth session returns dismiss before browser closes

šŸ› Bug Report

Summary of Issue

When using ā€œuseAuthRequest()ā€, the response is of type: ā€œdismissā€ even before the browser window closes when the flow is completed. This only happens with standalone build for android, both expo environment and iOS works perfectly. I have tried all fixes in the related issue #6679, and we would like to not use proxy, so startAsync() wont work.

Environment - output of expo diagnostics & the platform(s) you’re targeting

  • Only on android in standalone release mode
  • Both in simulator, on device and trough play store internal testing

Expo CLI 3.23.3 environment info: System: OS: Windows 10 10.0.18362 Binaries: Node: 12.18.0 - C:\Program Files\nodejs\node.EXE npm: 6.14.7 - C:\Program Files\nodejs\npm.CMD npmPackages: expo: ~38.0.8 => 38.0.9 react: ~16.11.0 => 16.11.0 react-dom: ~16.11.0 => 16.11.0 react-native: https://github.com/expo/react-native/archive/sdk-38.0.2.tar.gz => 0.62.2 react-native-web: ~0.11.7 => 0.11.7

Reproducible Demo

Link to code that reproduces the issue: https://snack.expo.io/@simenbakken/auth-session-bug

Steps to Reproduce

Expected Behavior vs Actual Behavior

Expected: Browser opens on login button press and user enters credentials. When login flow is completed, the browser closes, and the text field is updated with response from Azure.

Actual: Browser opens on login button press and user enters credential. When login flow is completed, the browser closes, and the text field is always {ā€œtypeā€:ā€œdismissā€} even if login is successful (only and android as discussed above, iOS and expo dev works as expected). It seams like dismissed is returned even before browser is opened, as sometimes if i create an Alert.alert() after await promptAsync(), i can catch a glimt of the alert as the browser opens.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 5
  • Comments: 30 (8 by maintainers)

Most upvoted comments

I’ve been struggling with this too. From what I’ve found, the redirectUri scheme has to match your Android package (ex. for package name com.example the redirectUri would be com.example:/oauthredirect). After making my scheme key match the Android package, I was able to sign in successfully, but there was another problem. After successful login I was prompted to select the app with which I’d like to continue with, and there were 2 options available - both being my app, with the difference being that only one works. Not sure how to get around this one, so I guess I’ll be switching to expo-google-app-auth for the time being.

Spent a bit more time with this and I was able to fix the issue we were having.

Turns out Android production builds require something to be after the custom scheme. For example, app-name:// will not work in production Android builds, but app-name://auth will work.

Though, the caveat is that you have to also fix the additional bug in the expo library that was adding an extra / that was causing issues changing the redirect url to be app-name:///auth so the fix was to add auth to the redirect url, AND to remove the extra slash that the expo library adds.

Broken code: const redirectURL = Linking.makeUrl();

And, this was our fix: const redirectURL = Linking.makeUrl('auth').replace('///', '//');

Thanks @SimenBakken and @rikkitissier !

I too am experiencing this issue. I don’t have uppercase letters in the redirect uri, and I don’t have 3 slashes in a row.

It works on iOS but on Android it doesn’t work in emulator or in production.

EDIT: Like @rikkitissier above, I am using WebBrowser.openAuthSessionAsync without useAuthRequest.

Also having the same issue, though I’m using WebBrowser.openAuthSessionAsync. Works everywhere except the production Android. None of the existing workarounds/suggested fixes have worked thus far.

@EvanBacon Would it make sense to add a second intent-filter to the manifest, or is sharing the net.openid.appauth.RedirectUriReceiverActivity intent intentional?

I was able to get this to work by fixing the conflict with net.openid.appauth.RedirectUriReceiverActivity in the manifest via apktool.

First I replaced <data android:scheme="com.my.app" android:path="oauthredirect"/> with <data android:scheme="com.my.app" android:host="*" android:path="/oauthredirect"/>, because the path is ignored if host is not defined and path must start with a /. Also see docs on intent filters. This allows a second intent to handle com.my.app alongside the existing openid one.

Next I added a new intent filter under the host.exp.exponent.MainActivity activity:

<intent-filter>
  <action android:name="android.intent.action.VIEW"/>
  <category android:name="android.intent.category.DEFAULT"/>
  <category android:name="android.intent.category.BROWSABLE"/>
  <data android:host="*" android:path="/expo_oauthredirect" android:scheme="com.my.app"/>
</intent-filter>

Lastly I used patch-package to update node_modules/expo-auth-session/build/providers/Google.js to match the new intent with /// to send expo_oauthredirect as a path instead of a host/authority:

diff --git a/node_modules/expo-auth-session/build/providers/Google.js b/node_modules/expo-auth-session/build/providers/Google.js
index 9cac987..6fba1b4 100644
--- a/node_modules/expo-auth-session/build/providers/Google.js
+++ b/node_modules/expo-auth-session/build/providers/Google.js
@@ -145,7 +145,7 @@ export function useAuthRequest(config = {}, redirectUriOptions = {}) {
             return config.redirectUri;
         }
         return makeRedirectUri({
-            native: `${Application.applicationId}:/oauthredirect`,
+            native: `${Application.applicationId}:///expo_oauthredirect`,
             useProxy,
             ...redirectUriOptions,
         });

To update the apk:

apktool decode myapp-original.apk
vim myapp-original/AndroidManifest.xml
apktool build myapp-original -o myapp.apk
expo credentials:manager -p android
/path/toAndroid/Sdk/build-tools/$VERSION/apksigner sign -ks @username__myapp.bak.jks myapp.apk
/Android/Sdk/platform-tools/adb install myapp.apk

To test the intent-filters in the manifest:

adb shell pm resolve-activity --components 'com.my.app:///expo_oauthredirect'

Issue still persists. On Android emulator AND physical device, openAuthSessionAsync resolves with {type: ā€œdismissā€} right away.

Okay so I have completed some extensive testing, and it looks like the problem only occurs if the redirectUrl object in the snack above contains capital letters. As long as all letters in redirectUrl are lower case everything seams to work as expected. So to sum up:

  • redirectUrl: ā€œtestapp://LoginStackā€ always returns dismissed
  • redirectUrl: ā€œtestapp://loginstackā€ works as expected

@Reverendheat Hope this fixes the issue your having as well.