react-native-azure-auth icon indicating copy to clipboard operation
react-native-azure-auth copied to clipboard

Glitch - loop to redirect to login popup, not redirect to app

Open ioeldev opened this issue 2 years ago • 14 comments

I have implemented an azure login button, the flow is working well on iOS, but on Android there is a glitch that I don’t manage to fix, maybe you have already faced this issue so i take my shot

The button trigger the login popup from Microsoft as expected, but once logged in, instead of redirecting to the app it just bring me to the same page in a loop.. (Again this is not happening on IOS)

Here is a video screen of the glitch.

My manifest is the basic showed in the doc.

<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="{applicationId}"
                    android:pathPrefix="/android/callback"
                    android:scheme="{applicationId}" />
</intent-filter>

And my code is very basic, i create new AzureAuth instance and pass my client id. On the login button i call the authorize method with the most basic scope.

const azureAuth = new AzureAuth({
    clientId: azureGoogleEnvConfig.azure.clientId,
});
const tokens = await azureAuth.webAuth.authorize({
                scope: 'openid profile User.Read',
});            
console.log(tokens)

ioeldev avatar May 29 '23 07:05 ioeldev

Another weird behavior: I tried to add the .staging suffix to the intent-filter on AndroidManifest.xml (as we append it when testing our app locally) , and added the new redirect uri in the Azure portal (com.ourApp.staging://com.ourApp.staging/android/callback) I got to two apps options in the "open the link with" to redirect to the app, both called the same:

  • If i click on the first, it does the same behavior (loop to the same page)
  • If i click on the second to redirect to the app but cancel the login request (and receive {error_description: "User cancelled the Auth", error: "aa.session.user_cancelled"} )

ioeldev avatar May 29 '23 07:05 ioeldev

Try to replace {applicationId} in your manifest with a string literal and check if it helps.

vmurin avatar May 29 '23 11:05 vmurin

what do you mean ? In my code this is not applicationId, it is literally com.myApp.staging

ioeldev avatar May 29 '23 12:05 ioeldev

If you don't have any variable or placeholder and just string there, double check the app registration - you should have the same scheme/pathPrefix in you callback URI.

vmurin avatar May 29 '23 12:05 vmurin

I tried to create a sample app and it is working as expected on both os. It seems that the app we created in our company cause the glitch but i can't seem to figure what/where... Here are some details about our config:

android/build.gradle

...

ext {
    compileSdkVersion = 33
    targetSdkVersion = 31
    minSdkVersion = 26
    buildToolsVersion = "29.0.2"
    supportLibVersion = buildToolsVersion
    playServicesVersion= "18.0.0"
    androidMapsUtilsVersion = "2.3.0"
}

...

gradle-wrapper.properties

#Tue Mar 10 17:31:53 EDT 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.3-all.zip

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.OUR_APP_NAME.android">

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

    <supports-screens
        android:anyDensity="true"
        android:largeScreens="true"
        android:normalScreens="true"
        android:resizeable="true"
        android:smallScreens="true"
        android:xlargeScreens="true" />

    <!-- maps -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.VIBRATE" />

    <!-- push -->
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

    <!-- OpenGL ES version 2 -->
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />

    <application
        android:name=".Application"
        android:allowBackup="true"
        android:largeHeap="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name_key"
        android:theme="@style/AppTheme"
        android:networkSecurityConfig="@xml/network_security_config">

        <activity android:exported="true" android:name=".MainActivity" android:theme="@style/AppTheme.SplashScreen" android:launchMode="singleTask">
            <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:host="com.OUR_APP_NAME.android"
                    android:pathPrefix="/android/callback"
                    android:scheme="com.OUR_APP_NAME.android" />
            </intent-filter>   
        </activity>

        <receiver android:name=".push.ActionReceiver"></receiver>
        <service
            android:name="com.OUR_APP_NAME.android.push.ListenerService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
        <service
            android:name="com.OUR_APP_NAME.android.push.RegistrationIntentService"
            android:permission="android.permission.BIND_JOB_SERVICE"
            android:exported="false" />
        <uses-library
            android:name="com.google.android.maps"
            android:required="false" />

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google_maps_api_key" />

        <activity
            android:exported="true"
            android:name=".controllers.dashboard.DashboardActivity"
            android:configChanges="orientation|screenSize"
            android:label="@string/app_name"
            android:launchMode="singleTop"
            android:screenOrientation="portrait"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <activity
            android:name=".controllers.login.ReactLoginActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait"
            android:label="@string/title_activity_login"
            />
        <activity
                android:name=".controllers.alertdetail.ACADetailActivity"
                android:configChanges="orientation|screenSize"
                android:screenOrientation="portrait"
                android:label="">
            <meta-data
                    android:name="android.support.PARENT_ACTIVITY"
                    android:value=".controllers.dashboard.DashboardActivity" />
        </activity>
        <activity
                android:name=".controllers.alertdetail.AlertDetailActivity"
                android:configChanges="orientation|screenSize"
                android:screenOrientation="portrait"
                android:label="">
            <meta-data
                    android:name="android.support.PARENT_ACTIVITY"
                    android:value=".controllers.dashboard.DashboardActivity" />
        </activity>
        <activity
            android:name=".controllers.alertdetail.NotificationACADetailActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait"
            android:label="">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".controllers.dashboard.DashboardActivity" />
        </activity>
        <activity
            android:name=".controllers.alertdetail.NotificationAlertDetailActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait"
            android:label="">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".controllers.dashboard.DashboardActivity" />
        </activity>
        <activity android:exported="true" android:name=".controllers.shared.DeepLinkActivity" android:launchMode="singleTask" android:noHistory="true">
            <intent-filter android:label="@string/app_name" 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="https" />
                <data android:host="app.OUR_APP_NAME.com" />
                <data android:host="corp.OUR_APP_NAME.com" />
                <data android:host="ps.OUR_APP_NAME.com" />
                <data android:host="gov.OUR_APP_NAME.com" />
                <data android:host="firstalert.OUR_APP_NAME.com" />
                <data android:host="news.OUR_APP_NAME.com" />
                <data android:host="stage.OUR_APP_NAME.com" />
                <data android:host="r-stage.OUR_APP_NAME.com" />
                <data android:host="redirect-stage.OUR_APP_NAME.com" />
                <data android:host="redirect.OUR_APP_NAME.com" />
            </intent-filter>
        </activity>
        <activity
            android:name=".controllers.settings.AccountSettingsActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait"
            android:label="@string/title_activity_account_settings"
            android:parentActivityName=".controllers.dashboard.DashboardActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".controllers.dashboard.DashboardActivity" />
        </activity>
        <activity
            android:name=".controllers.search.SearchActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait"
            android:label="" />
        <activity
            android:name=".controllers.settings.SettingsActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait"
            android:label="@string/title_activity_settings" />
        <activity
            android:name=".controllers.messages.MessageDetailActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait"
            android:label="" />
        <activity
            android:name=".controllers.settings.DashboardSettingsActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait"
            android:label="@string/title_activity_dashboard_settings" />
        <activity
            android:name=".controllers.settings.CustomDashboardSettingsActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait" />
        <activity
            android:name=".controllers.twitterUser.TwitterUserDetailActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait" />
        <activity
            android:name=".controllers.map.ReactMapActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait" />
        <activity
            android:exported="true"
            android:name=".controllers.login.ReactTermsOfUseActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="com.intent.action.TERMS.${termsOfUseTarget}" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <activity
            android:name=".controllers.settings.ResetPasswordActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="adjustResize"/>
        <activity
            android:name=".controllers.settings.ReactWatchlistEditActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait" />
        <activity
            android:name=".controllers.settings.ContrastSettingsActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait" />
        <activity
            android:name=".controllers.settings.BetaFeaturesActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait" />
        <activity
            android:name=".controllers.settings.LocalizationSettingsActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait" />
        <activity
            android:name=".controllers.settings.ReactNotificationSettingActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait" />
        <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
        <activity
            android:name=".controllers.map.ProximitySelectionActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="adjustResize" />
        <activity
            android:name=".controllers.login.OnboardingActivity"
            android:configChanges="orientation|screenSize"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="adjustResize" />

    </application>
    <queries>
        <intent>
            <action android:name="android.support.customtabs.action.CustomTabsService" />
        </intent>
    </queries>
</manifest>

I mention that when i console.log azure.auth.redirectUri i got the same as the one in app registration and the same as what is in the intent-filter, meaning that the redirectUris matches

ioeldev avatar May 29 '23 14:05 ioeldev

Please check the answer below. I suppose it is your case too:

https://github.com/vmurin/react-native-azure-auth/issues/94#issuecomment-656315746

vmurin avatar May 29 '23 15:05 vmurin

I am not sure, because in my case the redirect uri match the one in the app registration

ioeldev avatar May 29 '23 15:05 ioeldev

Just try to use the additional parameter redirectUri in the initialization:

const azureAuth = new AzureAuth({
    clientId: 'YOUR_CLIENT_ID',
    redirectUri: 'your redirect URI here'
});

vmurin avatar May 29 '23 15:05 vmurin

i tried to use the redirectUri param in the initialization, and it did help returning to the app, but it gives the "User cancelled the auth" error now..

I don't understand what could cause this trouble, since i just did a test by creating a new react-native app, and the flow work perfectly. Feel like something is wrong in our existing app..

ioeldev avatar May 30 '23 08:05 ioeldev

@vmurin Do you think it's ok to delete the <intent-filter> if I use the redirectUri parameter in the AzureAuth initialization ?

ioeldev avatar May 30 '23 11:05 ioeldev

@vmurin Do you think it's ok to delete the <intent-filter> if I use the redirectUri parameter in the AzureAuth initialization ?

no, without intent the android OS will not know which app should be called upon callback. It is your connection between URI and the app.

vmurin avatar May 30 '23 12:05 vmurin

remove android:pathPrefix from intent-filter and update your intent filter to the following it will fix your issue

<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='${applicationid}'
              android:scheme="msauth" />
</intent-filter>

iamsaadMehmood avatar Aug 17 '23 12:08 iamsaadMehmood

anyone figured out how to fix it? For me there is also two apps options in the "open the link with" to redirect to the app, both called the same:

  • If i click on the first, it works correctly
  • if I click on the second, it loops

I suspect that such behavior is due to having two intent-filters which are both catching redirect, but no, for my application there are only two intent filters: main one, and the one which is explained in readme for this library.

I suspect that indeed my main intent filter is somehow catching the redirect, even though in no way it should be able to catch it. It's looking like this:

<intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>

But why it's happening for my app and not for others?

nshaposhnik avatar Nov 06 '23 05:11 nshaposhnik

what worked for me is to use custom redirect uri, different to default one (your app's package name). Then two redirect options disappear.

nshaposhnik avatar Nov 13 '23 11:11 nshaposhnik