Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

authorize() returns error 'Data intent is null' on Android #494

Closed
KristineTrona opened this issue Apr 1, 2020 · 58 comments
Closed

authorize() returns error 'Data intent is null' on Android #494

KristineTrona opened this issue Apr 1, 2020 · 58 comments

Comments

@KristineTrona
Copy link

KristineTrona commented Apr 1, 2020

Issue

Every time I call authorize() method I get Error: Data intent is null, whenever running on an Android emulator with 'R' operating system. Any idea what could be causing this error and how to fix it?

const config = {
  warmAndPrefetchChrome: Platform.OS === 'android',
  issuer,
  clientId,
  redirectUrl: 'testSchema://oauth/redirect',
  scopes: ['openid', 'profile', 'api', 'offline_access'],
  usePKCE: true,
};

export const authenticate = async () => {
  try {
    const result = await authorize(config);
    console.log('authorized')  // Execution never makes it to this line
    return result
  } catch (e) {
    throw new Error(e);
  }
};

In android/app/builde.gradle


    defaultConfig {
        applicationId "com.testApp"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName "1.0.0"
        resValue "string", "build_config_package", "com.testApp"
        manifestPlaceholders = [
            appAuthRedirectScheme: 'testSchema'
        ]

    }

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.testApp">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:allowBackup="false"
      android:theme="@style/AppTheme">
      <activity
        android:name=".SplashActivity"
        android:theme="@style/SplashTheme"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
            <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
        </intent-filter>
      </activity>
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:screenOrientation="portrait"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
        android:windowSoftInputMode="adjustResize"
        android:exported="true">
      </activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
      <provider
		    android:name="com.vinzscam.reactnativefileviewer.FileProvider"
		    android:authorities="${applicationId}.provider"
		    android:exported="false"
		    android:grantUriPermissions="true">
		    <meta-data
		    	android:name="android.support.FILE_PROVIDER_PATHS"
		    	android:resource="@xml/file_viewer_provider_paths"
		    />
	    </provider>
    </application>

</manifest>

Fails on all 3 of these, but works fine on 'Q' or 'Pie' operating systems:
Screenshot 2020-04-02 at 15 23 22

Environment

  • Your Identity Provider: IdentityServer 4
  • Platform that you're experiencing the issue on: Android (specific to version 'R')
  • Are you using Expo? No
@thilinawarnakula
Copy link

@KristineTrona did you find a fix to this

@KristineTrona
Copy link
Author

@thilinawarnakula no, but I think it happens only on Android 11.0.0 (R), which has not been released to the public yet.

@Shpadoinkle
Copy link

@KristineTrona Hi Kristine,
Did you end up solving this issue?

@KristineTrona
Copy link
Author

Hi, no, unfortunately I did not.

@Shpadoinkle
Copy link

Not sure if it will help others,
But our issue was a double up of the redirectUrl, the documentation mentions two places you can put it. In the build gradle or manifest.. But you can only do one or the other.
Putting it in both places is what broke it for us.

@harunsmrkovic
Copy link
Contributor

I resolved this by adding the link prefix into the build.gradle file

manifestPlaceholders = [
            appAuthRedirectScheme: 'com.mobileubdiapp',
            appAuthRedirectScheme: 'ubdi'
        ]

e.g. If the redirect URL is ubdi://connect, then you need to have ubdi listed here

@kadikraman
Copy link
Contributor

Thank you for posting your solution @Shpadoinkle and @harunsmrkovic !

@KristineTrona Is this still an issue for you? I can't reproduce this on my emulator. This is the Example app with the Identity Server 4 configuration running on Pixel 2 with API 30.

Screenshot 2020-08-13 at 14 29 30

android

@aliiqbal436
Copy link

I am facing this same issue.

@adailson2
Copy link

I have the same issue and I tried all solutions in this thread, but I have not success.

@sharadkatre1995
Copy link

I am also facing the same issue did anyone gets anything.
Thanks

@AlkanV
Copy link

AlkanV commented Oct 21, 2020

i am facing same issue

@yberstad
Copy link

From our production logs I see that some of our customers are getting this error, but I'm having a hard time reproducing the error. Does anyone have an "recipe" how to reproduce this error?

I have tried to use these steps to reproduce it, but no luck #130 (comment)

(Our app is using android:launchMode="singleInstance" instead of android:launchMode="singleTask", not sure if this has anything to do with this error)

@AlkanV
Copy link

AlkanV commented Nov 17, 2020

Hello @yberstad ,

the problem here is that, react-native-app-auth is not getting data from redirectUri. this is caused because of wrong configuration in intents.
below you can find how i get rid of this error.

      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
      <intent-filter android:label="@string/app_name">
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
       <data android:scheme="your.deeplink.scheme" />
      </intent-filter>
    </activity>
	<activity
        android:name="net.openid.appauth.RedirectUriReceiverActivity">
    <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:scheme="your.deeplink.scheme.for.oauth"  />
    </intent-filter>

basically, rn-app-auth gets data from redirectUri via deeplink. so you need to configure rn-app-auth to look correct deep linking scheme.

// in build.gradle
defaultConfig{
...
manifestPlaceholders = [
            appAuthRedirectScheme: 'your.deeplink.scheme.for.oauth'
        ]
}

@yberstad
Copy link

@AlkanV thank you so much for your very quick response, much appreciated!

This is our current config:

{
  issuer: https://identity-dev.sharpnet.no,
  clientId: "sharpnetapp",
  redirectUrl: "sharpnet://signin-oidc",
  scopes: ["openid", "appdevice", "applogin"],
  additionalParameters: {}
};

/app/build.gradle:

manifestPlaceholders = [
    appAuthRedirectScheme: 'sharpnet'
]

And here is our current intent-filter's in AndroidManifest.xml:

<activity
    android:name=".MainActivity"
    android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
    android:label="@string/app_name"
    android:theme="@style/SplashTheme"
    android:launchMode="singleInstance"
    android:windowSoftInputMode="adjustResize">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
    </intent-filter>
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
    </intent-filter>
</activity>

Should I change it to this?

<activity
    android:name=".MainActivity"
    android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
    android:label="@string/app_name"
    android:theme="@style/SplashTheme"
    android:launchMode="singleInstance"
    android:windowSoftInputMode="adjustResize">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
    </intent-filter>
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="sharpnet" />
    </intent-filter>
</activity>
<activity android:name="net.openid.appauth.RedirectUriReceiverActivity">
    <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:scheme="sharpnet"  />
    </intent-filter>
</activity>

Just a clarification, we are only getting "Data intent is null" for some our Android users. It is working for the majority of our users.

@netanelh
Copy link

@yberstad did you find why it happens only to some users?

@yberstad
Copy link

yberstad commented Jan 6, 2021

@netanelh sorry, did not see your post before now.

No, we have not figured this out yet. I have been able to reproduce the error (but not in a way I think the user does it):

  1. Open the app
  2. Start the authentication process (oidc web page)
  3. Press home button
  4. Open the app again
  5. Then I get the "Data intent is null"

I suspect that this is due to that we get a new instance of the app (using android:launchMode="singleInstance") and that the original intent is lost?

If i look in node_modules/react-native-app-auth/android/src/main/java/com/rnappauth/RNAppAuthModule.java I see this code:
@Override public void onNewIntent(Intent intent) { }

The new intent is not "saved", but I do not know if this has anything to do with? Again, I do not think this is what the users experiencing this error is actually doing.

If anyone have some new insights on this issue, it would be much appreciated!

@DanielSchwartz89
Copy link

Any possible solution or workaround? @yberstad

@yberstad
Copy link

@DanielSchwartz89, not to my knowledge unfortunately.

@Aleksefo
Copy link

Aleksefo commented Feb 2, 2021

We have exactly the same issue in our project. @yberstad your reproduction steps are correct.

To trigger "Data intent is null" error, the user must:

  1. Open the app (the example app will do)
  2. Start the authentication process (web page)
  3. Press home button
  4. Open the app again (through Home screen icon)
  5. Then the webview is automatically closed and the user sees the error.

To avoid the issue, the user, during step 4, must use Recent apps/Overview button/gesture to navigate back to the app.

For some reason, there is a difference in app-auth behavior depending on the user opening the app through the Home screen or Recent apps. One case always fails, the other succeeds.

We suspect it is due to onResume() method triggering finish() in AuthorizationManagementActivity.java of AppAuth-Android.
https://github.com/openid/AppAuth-Android/blob/907ebbd890738e47c0c0c5d04fc6dfa6c449891b/library/java/net/openid/appauth/AuthorizationManagementActivity.java#L211

The issue is quite critical since in our case we need to use third-party banking apps to authenticate, so the users have to switch between apps. At the moment we have to manually instruct the users to use "Recent apps" instead of the home button, but that is not a good solution.

@Aleksefo
Copy link

Aleksefo commented Feb 3, 2021

The fix seems to be to change android:launchMode to "singleTop" in AndroidManifest.xml
@yberstad, @DanielSchwartz89 @netanelh

@yberstad
Copy link

yberstad commented Feb 5, 2021

@Aleksefo, thank you so much for your info, very helpful!

I was initially sceptic to change the android:launchMode, because I was not sure what implications it could have.

But after trying to grasp the concept, I cannot see that would have any implications to change it (especially since we only have one activity in our RN application).

I watched this series regarding the concept of lauchMode, https://www.youtube.com/watch?v=gRub-Pm_A0Q&t=36s, which was very helpful.

@Aleksefo
Copy link

Aleksefo commented Feb 5, 2021

@yberstad I've noticed some issues with this approach though:
If the app is opened from Google play(install then open), then the first Bank login(where you have to navigate between apps) fails. Follow up logins are successful using the "home screen icon" method. (That's the issue with android:launchMode )
The same scenario but using "recent apps" instead of "home screen icon" succeeds as before.
If the app is opened for the first time from home screen, then everything works no matter what.
If the app is opened from Google play, but the user logins with Email(no need for switching apps), then all works.

We also have a bank which prompts a user for extra input after the authentication.
It is more unpredictable(probably due to an extra step).
When user returns(with "home screen icon") to the app it shows RN part instead of the webview. If the user clicks the Android back button, then the bowser is shown with extra final step of authentication. (That's the issue with android:launchMode )
After clicking authenticate, the user is shown the RN part again, but login showed as failed.
If the user closes the app and opens it again, they are authenticated and everything works.

So overall I think it's a big win, since it doesn't affect successful logins, but fixes previously unsuccessful login almost without issues.

@yberstad
Copy link

yberstad commented Feb 5, 2021

@Aleksefo, thanks for a nice summary of various use cases. I'll bring that with me while testing our app 😄

@Aleksefo
Copy link

Aleksefo commented Feb 5, 2021

@yberstad Sure, let me know if you'll find any extra issues.

I think the next step would be to modify either react-native-app-auth or app-auth-android to disable onResume() methods that break the authentication and then apply a custom patch to get rid of the issue for good.
"android:launchMode" is more of a hack than a long term solution, so fixing the issue directly would be preferable.

@yberstad
Copy link

yberstad commented Feb 5, 2021

@Aleksefo, I'll definitely get back to you if I find some issues regarding this! Again, thanks for letting me know of your findings!

@Aleksefo
Copy link

The issue is not related to Auth library, but android in general: https://issuetracker.google.com/issues/36907463
Final solution:

AndroidManifest.xml:
android:launchMode="standard"

MainActivity.java

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (!isTaskRoot()) {
      finish();
      return;
    }
  }

The fix works in most of the cases except when the app is opened from an unusual source (react-native start, Google play, etc.). In that case, using home screen icon to return to the app will cause extra activity on top of the stack which cannot be removed using something like React Navigation, for example.
It might be possible to write a native module with a function to close the activity. The solution I made is this function to close the app if the user successfully authenticated, but the login screen is shown again on that extra activity. The app is closed, but the next time you open it, the app will be authenticated already.

Somewhere where you have login button:

    const onPress = () => {
      if (accessToken && Platform.OS === "android") {
        sendEvent({
          event_name: "onboarding_exitApp_pressed",
        });
        BackHandler.exitApp();
      } else {
        login();
      }
    }

@badsyntax
Copy link
Contributor

badsyntax commented Mar 12, 2021

It seems this ticket is diverging into different issues. The issue I'm referring to is the Error: Data intent is null error.

The problem I experienced was due to having deeplink integration already in place, using reactnavigation.

You won't see this issue if you have not defined other intent-filters for the same auth scheme.

Based on the reactnavigation instructions, I have the following set in my AndroidManifest.xml:

<activity
  android:name=".MainActivity"
  android:label="@string/app_name"
  android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
  android:launchMode="singleTask"
  android:windowSoftInputMode="adjustResize">
  <intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
  <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:scheme="com.myapp" />
  </intent-filter>
</activity>

And for react-native-app-auth, I have set the following in my build.gradle:

android {
    defaultConfig {
        manifestPlaceholders = [
            appAuthRedirectScheme: 'com.myapp'
        ]
    }
}

Note that adding the above effectively is the same as explicitly adding a new activity & intent filter like so:

<activity
        android:name="net.openid.appauth.RedirectUriReceiverActivity"
        tools:node="replace">
    <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:scheme="com.myapp"/>
    </intent-filter>
</activity>

So now we have two activities handling the same scheme.

The result of this is that after logging in, I'm presented with an "Open With" prompt that shows my app twice. I assume because there are now effectively two intent-filter's for the same scheme.

If I select the app that's handling the .MainActivity activity, I get the Error: Data intent is null error. If I select the other app, the authentication works.

To "fix" this, I followed @AlkanV's advice and used a different scheme for the authentication redirect url, set in the build.gradle:

android {
    defaultConfig {
        manifestPlaceholders = [
            appAuthRedirectScheme: 'com.myapp.auth'
        ]
    }
}

I then updated my redirect url to reflect the auth redirect scheme. After logging in, everything works. I don't get the "open with" prompt and I don't get the auth error. I don't like that the app handles two different deeplinking schemes, but I'm not sure if this is a problem or not.

I will create a new ticket asking the library authors to update the example to include reactnavigation. Issue here: #611

@activebiz
Copy link

This is still issue for me and problem is that its only happending on some android devices!

@anisimov74
Copy link

anisimov74 commented Sep 23, 2021

@badsyntax thank you for the quick response. I just typed a wrong string. It's definitely com.myapp.oauth.
I tried many variants with no luck.
If I don't set appAuthRedirectScheme in build.gradle, I can't make a project.
How did you do that?

@badsyntax
Copy link
Contributor

@anisimov74 what do you mean you can't make a project? What is the error?

@anisimov74
Copy link

@badsyntax that seems to be some sort of cache problem. After switching between branches, that error has gone.
I have the only change in Manifest.xml.
Still no redirect. Any thoughts?

<activity
        android:name="net.openid.appauth.RedirectUriReceiverActivity"
        tools:node="replace">
        <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:scheme="com.mobile.app.oauth" android:host="landing.url"/>
        </intent-filter>
      </activity>

@badsyntax
Copy link
Contributor

@anisimov74 does the redirectUrl in the config you pass to authorise() match the scheme?

@anisimov74
Copy link

@badsyntax yes it is. It's com.mobile.app.oauth://landing.url

@anisimov74
Copy link

anisimov74 commented Sep 23, 2021

@badsyntax and I see that in logs

2021-09-23 15:49:06.940 2046-2449/? I/ActivityTaskManager: START u0 {act=android.intent.action.VIEW cat=[android.intent.category.BROWSABLE] dat=com.mobile.app.oauth://landing.url?code=XXXXXXXXXXXXXX flg=0x14000000 cmp=com.mobile.app/net.openid.appauth.RedirectUriReceiverActivity (has extras)} from uid 10114

@badsyntax
Copy link
Contributor

Can you try without the landing.url host? So remove android:host="landing.url". That's really the only difference I can tell. When you say "still no redirect", what exactly is happening after you authenticate?

@anisimov74
Copy link

@badsyntax tried without android:host="landing.url. After entering credentials I see a Chrome tab.

@badsyntax
Copy link
Contributor

I'm out of ideas. IMO it would be useful if this repo has a reactnavigation example that people can refer to.

@anisimov74
Copy link

@badsyntax thank you for helping me! Will try more variants.

@anisimov74
Copy link

anisimov74 commented Sep 29, 2021

I figured out the cause of the problem. There is a In Manifest.xml android:taskAffinity="", which should prevent possible phishing via task hijacking.
#674

@stanjhae
Copy link

stanjhae commented Oct 17, 2021

Incase you're using firebase deep links or your deep link is more like "https://www.blah.com/oauth" instead of the generic "com.blah.app", you can try this

<activity
  android:name="net.openid.appauth.RedirectUriReceiverActivity">
    <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:scheme="https" android:host="www.blah.com"android:pathPrefix="/oauth" />
    </intent-filter>
</activity>

Note: In the case of firebase, your redirectUrl should be
"https://yourFirebaseUrl?link=theActualDeepLink(https://www.blah.com/oauth)&theRestOfTheUrl(&apn='blah'...etc)"

You don't need to specify appAuthRedirectScheme in the build.gradle as it'll resolve to having two activities.

I no longer have the Data intent is null error.

However, I now have a Response state param did not match request state error. I'm trying to authenticate with Spotify so It could be an unrelated issue.

@EvoluWil
Copy link

1
change package name in redirectUrl
com.YOUR_APP => com.YOUR_APP.auth

const config = {
      issuer: 'https://accounts.google.com',
      clientId: 'YOUR_clientId',
      redirectUrl: 'com.YOUR_APP.auth:/oauth2callback', 
     scopes: ['email', 'profile'],
};

2
change the package name on the google website
com.YOUR_APP => com.YOUR_APP.auth

3
in build.gradle

android {
    defaultConfig {
        manifestPlaceholders = [
            appAuthRedirectScheme: 'com.YOUR_APP.auth'
        ]
    }
}

@Jay-A-McBee
Copy link
Contributor

Closing this due to subject drift - sounds like a configuration issue. Creating redundant intent handlers by using both the manifest and manifestPlaceholders in build.gradle.

@mrjosshi
Copy link

mrjosshi commented Aug 24, 2022

Any update on this ? I am still facing same issue. I have applied all above changes but still facing same issue can some one help

@zeinabzahran
Copy link

Same issue. Any updates?

@xenialugovaya
Copy link

Same issue, double checked configuration. Has anyone figured out how to fix this?

@RubenPM-dev
Copy link
Contributor

I had this issue recently and it turns out I was using characters on my scheme that are not allowed, such as ' / '.

Fount some useful information about this on this Flutter rep:
https://github.com/LinusU/flutter_web_auth#troubleshooting

@witherBattler
Copy link

I have this issue as well

@dangnguyen1004
Copy link

I have this issued as well

1 similar comment
@dangnguyen1004
Copy link

I have this issued as well

@AbbasTheReckoner
Copy link

AbbasTheReckoner commented Apr 7, 2023

I resolved this by adding the link prefix into the build.gradle file

manifestPlaceholders = [
            appAuthRedirectScheme: 'com.mobileubdiapp',
            appAuthRedirectScheme: 'ubdi'
        ]

e.g. If the redirect URL is ubdi://connect, then you need to have ubdi listed here

can we add multiple appAuthRedirectScheme to manifestplaceholder @harunsmrkovic ?

@avinash-capsitech
Copy link

avinash-capsitech commented Sep 13, 2023

I tried all solutions but getting same issue "Data intent is null".
If anyone have more suggestion or solution then please describe ??

@4RGUS
Copy link

4RGUS commented Sep 18, 2023

I also tried all of the solutions above and still I have the same issue.

@avinash-capsitech
Copy link

i resolved this by following steps:--

  1. Remove manifestPlaceholders from build.gradle(Module:app).
defaultConfig {
        applicationId "com.dummy"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName "1.0"
//        manifestPlaceholders = [
//                appAuthRedirectScheme: 'com.gumtestapp',
//                appAuthRedirectScheme: 'ao'
//        ]
    }
  1. Changes in manifest :

Add to application tag :

<activity
            android:name="net.openid.appauth.RedirectUriReceiverActivity"
            tools:node="replace"
            android:exported="true">
            <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:scheme="your_scheme"/>
            </intent-filter>

        </activity> 

Remove from main 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:scheme="your_scheme"/>
          </intent-filter>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests