openid / AppAuth-Android

Android client SDK for communicating with OAuth 2.0 and OpenID Connect providers.
https://openid.github.io/AppAuth-Android
Apache License 2.0
2.87k stars 887 forks source link

RedirectUriReceiverActivity not getting called when implement Asana auth #982

Open brunonavarro opened 1 year ago

brunonavarro commented 1 year ago

Configuration

Description

Good morning, I am setting up Asana Auth in the demo app and am having trouble redirecting to the android app after successful authentication.

When I use the URL https://protto.web.app/auth-success.html it stays in the browser, and the net.openid.appauth.RedirectUriReceiverActivity is not activated

The url is verified with .well-known/assetlinks.json and deployed in firebase.

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example.redirecturl",
    "sha256_cert_fingerprints":
    ["XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX"]
  }
}]
manifestPlaceholders = [
        'appAuthRedirectScheme': 'protto.web.app/auth-success.html'
]
<activity
    android:name="net.openid.appauth.RedirectUriReceiverActivity"
    android:exported="true"
    tools:node="replace">
    <intent-filter
        android:autoVerify="true"
        tools:targetApi="m">
        <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="protto.web.app"/>
        <data android:path="/auth-success.html"/>
    </intent-filter>
</activity>

The default URL format in the demo app doesn't work: net.openid.appauthdemo:/oauth2redirect.

Additional information Asana offers me the following route for native applications but I have no idea how to use it: urn:ietf:wg:oauth:2.0:oob

Please I need your help to finish configuring the redirect URL in the demo app.

Thanks.

agologan commented 1 year ago

The AppLink won't work if you type it in manully in the browser. It will however work if you tap the link in another page.

Another way to verify the AppLink works is using adb: adb shell am start -a android.intent.action.VIEW -d 'https://protto.web.app/auth-success.html'

If it doesn't work check your fingerprint, you may be signing the debug/production version of your app with an unexpected signature. If it does work, review the rest of your configuration again.

Btw, manifestPlaceholders.appAuthRedirectScheme is supposed to contain the scheme only, and it's not required since you replaced via tools:node="replace"

brunonavarro commented 1 year ago

The AppLink won't work if you type it in manully in the browser. It will however work if you tap the link in another page.

Another way to verify the AppLink works is using adb: adb shell am start -a android.intent.action.VIEW -d 'https://protto.web.app/auth-success.html'

If it doesn't work check your fingerprint, you may be signing the debug/production version of your app with an unexpected signature. If it does work, review the rest of your configuration again.

Btw, manifestPlaceholders.appAuthRedirectScheme is supposed to contain the scheme only, and it's not required since you replaced via tools:node="replace"

I have tried as you indicated by opening the link through a click and if it works but as part of the redirection after authentication, it does not return to the mobile application.

What exactly do you mean by:

Btw, manifestPlaceholders.appAuthRedirectScheme is supposed to contain the scheme only, and it's not required since you replaced via tools:node="replace"

agologan commented 1 year ago

You may be experiencing what I described here: https://github.com/openid/AppAuth-Android/issues/960#issuecomment-1631442105 Redirecting back to the app if the user is already authenticated requires some sort of user interaction. This is already implemented by some IdPs showing the user an account confirmation prompt or can be triggered by setting prompt to select_account or consent (if the IdP implements either) on the AuthenticationRequest.

About the other topic: appAuthRedirectScheme as the name suggests requires just the scheme (i.e. http, ftp or a custom scheme) as configures the redirect activity to: https://github.com/openid/AppAuth-Android/blob/master/library/AndroidManifest.xml#L31 If you're using AppLinks you're setting tools:node="replace" and adding your own full URL in the intent filter.

brunonavarro commented 1 year ago
android:autoVerify="true"
        tools:targetApi="m">

The problem is that the provider forces me to use https as a scheme or urn:ietf:wg:oauth:2.0:oob but with https it only stays in the browser and I never receive the result in onActivityResult I have tried adding a botton on the web to force the user to redirect to the application by reloading the page but that did not work either.

manifestPlaceholders = [
        'appAuthRedirectScheme': 'https'
]
<!-- Main activity -->
<activity
    android:name=".LoginActivity"
    android:theme="@style/AppTheme"
    android:windowSoftInputMode="stateHidden"
    android:exported="true"
    android:launchMode="singleTask">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

<!--            <nav-graph android:value="@navigation/main_navigation" />-->
</activity>
<activity
    android:name="net.openid.appauth.RedirectUriReceiverActivity"
    android:exported="true"
    tools:node="replace">
    <intent-filter
        android:autoVerify="true"
        tools:targetApi="m">
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="${appAuthRedirectScheme}" />
        <data android:host="protto.web.app"/>
        <data android:path="/auth-success.html"/>
    </intent-filter>
</activity>

Button in auth-success.html

<button onclick="location.reload()">Regresa a la aplicación</button>

image

I hope I have understood your indications, if so then there is any other option? Is there a difference in using my physical device instead of an emulator?

agologan commented 1 year ago

From what I could tell going to the same page or reloading is not considered navigation in Chrome thus triggering AppLinks.

Since you can edit auth-success.html put a link to <a href="/redirect.html"> and then change your <data android:path="/redirect.html"/>. This is of course just prototyping your final UX may look differently.

Also noticed you are using Auth0. The other solution I suggested above is passing in prompt - in their case they support consent which should tie the workflow together.

new AuthorizationRequest.Builder(
                mAuthStateManager.getCurrent().getAuthorizationServiceConfiguration(),
                mClientId.get(),
                ResponseTypeValues.CODE,
                mConfiguration.getRedirectUri())
                .setScope(mConfiguration.getScope())
                .setPrompt("consent");
brunonavarro commented 1 year ago

From what I could tell going to the same page or reloading is not considered navigation in Chrome thus triggering AppLinks.

Since you can edit auth-success.html put a link to <a href="/redirect.html"> and then change your <data android:path="/redirect.html"/>. This is of course just prototyping your final UX may look differently.

Also noticed you are using Auth0. The other solution I suggested above is passing in prompt - in their case they support consent which should tie the workflow together.

new AuthorizationRequest.Builder(
                mAuthStateManager.getCurrent().getAuthorizationServiceConfiguration(),
                mClientId.get(),
                ResponseTypeValues.CODE,
                mConfiguration.getRedirectUri())
                .setScope(mConfiguration.getScope())
                .setPrompt("consent");

I've tried, this and it still doesn't work. Neither with the click on the link, nor with adding the prompt.

Any other suggestions?

I really appreciate your help.

agologan commented 1 year ago

Here's my test setup on Auth0 that works with the demo app (ofc this is just some generated keystore for debug): https://appauth-demo-ac8b0.web.app/.well-known/assetlinks.json

{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "net.openid.appauthdemo",
    "sha256_cert_fingerprints":
    ["67:46:6D:C1:19:52:0A:6D:72:B3:47:21:3D:F4:5D:ED:63:29:DC:E4:3E:43:27:C2:AF:44:BB:98:84:5A:74:1E"]
 }

auth_config.json

{
  "client_id": "OLUK9s7mEjv1ZaEqKf049H0mTI4CladD",
  "redirect_uri": "https://appauth-demo-ac8b0.web.app/oauth2redirect",
  "end_session_redirect_uri": "https://appauth-demo-ac8b0.web.app/oauth2redirect",
  "authorization_scope": "openid email profile",
  "discovery_uri": "https://dev-rzfi5pan2vq6h75a.us.auth0.com/.well-known/openid-configuration",
  "https_required": true
}

In Auth0 application settings I have added https://appauth-demo-ac8b0.web.app/oauth2redirect to both Allowed Callback URLs and Allowed Logout URLs

Added prompt:consent to LoginActivity.java createAuthRequest()

AuthorizationRequest.Builder authRequestBuilder = new AuthorizationRequest.Builder(
  mAuthStateManager.getCurrent().getAuthorizationServiceConfiguration(),
  mClientId.get(),
  ResponseTypeValues.CODE,
  mConfiguration.getRedirectUri())
  .setScope(mConfiguration.getScope())
  .setPrompt("consent");
brunonavarro commented 1 year ago

Aquí está mi configuración de prueba en Auth0 que funciona con la aplicación de demostración (ofc esto es solo un almacén de claves generado para la depuración): https://appauth-demo-ac8b0.web.app/.well-known/assetlinks.json

{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "net.openid.appauthdemo",
    "sha256_cert_fingerprints":
    ["67:46:6D:C1:19:52:0A:6D:72:B3:47:21:3D:F4:5D:ED:63:29:DC:E4:3E:43:27:C2:AF:44:BB:98:84:5A:74:1E"]
 }

auth_config.json

{
  "client_id": "OLUK9s7mEjv1ZaEqKf049H0mTI4CladD",
  "redirect_uri": "https://appauth-demo-ac8b0.web.app/oauth2redirect",
  "end_session_redirect_uri": "https://appauth-demo-ac8b0.web.app/oauth2redirect",
  "authorization_scope": "openid email profile",
  "discovery_uri": "https://dev-rzfi5pan2vq6h75a.us.auth0.com/.well-known/openid-configuration",
  "https_required": true
}

En la configuración de la aplicación Auth0 he agregado tanto a las URL de devolución de llamada permitidas como a las URL de cierre de sesión permitidashttps://appauth-demo-ac8b0.web.app/oauth2redirect

Añadido a LoginActivity.java createAuthRequest()prompt:consent

AuthorizationRequest.Builder authRequestBuilder = new AuthorizationRequest.Builder(
  mAuthStateManager.getCurrent().getAuthorizationServiceConfiguration(),
  mClientId.get(),
  ResponseTypeValues.CODE,
  mConfiguration.getRedirectUri())
  .setScope(mConfiguration.getScope())
  .setPrompt("consent");

I have copied the same values, and in the manifest the intent-filter has been changed with the url of your auth_config.json but it still doesn't work:

  1. I got the error clientId not allowed
  2. Change clientId and discovery_url to my provider's and the same problem continues on the redirect.
  3. I thought about adding intent-filters with the url that I add in your web, but it didn't work. I still show the code below:
{
  "client_id": "XXXXXXXXXXXXX",
  "redirect_uri": "https://appauth-demo-ac8b0.web.app/oauth2redirect",
  "end_session_redirect_uri": "https://appauth-demo-ac8b0.web.app/oauth2redirect",
  "authorization_scope": "openid email profile",
  "discovery_uri": "https://app.asana.com/api/1.0/.well-known/openid-configuration",
  "https_required": true
}
<activity
    android:name="net.openid.appauth.RedirectUriReceiverActivity"
    android:exported="true"
    tools:node="replace">
    <intent-filter
        android:autoVerify="true"
        tools:targetApi="m">
        <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="appauth-demo-ac8b0.web.app"
          android:path="/oauth2redirect"/>
    </intent-filter>
    <intent-filter
        android:autoVerify="true"
        tools:targetApi="m">
        <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="appauth-demo-ac8b0.web.app"
            android:path="/net.openid.appauthdemo:/oauth2redirect"/>
    </intent-filter>
    <intent-filter
          android:autoVerify="true"
          tools:targetApi="m">
          <action android:name="android.intent.action.VIEW"/>
          <category android:name="android.intent.category.DEFAULT"/>
          <category android:name="android.intent.category.BROWSABLE"/>
          <data android:scheme="net.openid.appauthdemo:/oauth2redirect"/>
      </intent-filter>
</activity>
manifestPlaceholders = [
        'appAuthRedirectScheme': 'https'
]

url in my application registered with the provider.

image

agologan commented 1 year ago

It's not supposed to work, your signing key is not added to my debug environment: https://appauth-demo-ac8b0.web.app/.well-known/assetlinks.json I showed you this config as an example so you can figure out where you went wrong.

You mentioned Auth0 so I thought that's your primary IdP and wanted to help. But from your discovery URL you're trying to login into Asana.

You need to review the comments and docs again, the information should all be there.