AppAuth-Android icon indicating copy to clipboard operation
AppAuth-Android copied to clipboard

using registerForActivityResult

Open rwst opened this issue 4 years ago • 10 comments

Configuration

  • Version: 0.7.0
  • Integration: Kotlin

Description

Your README still uses the deprecated startActivityForResult() as example code. What would be the equivalent that uses the recommended resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) callback plus resultLauncher.launch(authIntent)?

rwst avatar Mar 06 '22 18:03 rwst

I just see the deprecated startActivityForResult is also used twice in the appauth demo. I would be interested to see how you resolve the deprecation there, as I could learn from it how to do it.

rwst avatar Mar 08 '22 17:03 rwst

Using version 0.11.1 I'm able to do everything without startActivityForResult.

I read & write auth state using a model that lives through app pause, I use the Auth Service to perform token request with a method reference to my function that receives a token response.

authService.performTokenRequest(authorizationResponse.createTokenExchangeRequest(), clientAuthentication, ::receivedTokenResponse)

If you're meaning for the AuthRequest you can just give it a PendingIntent for post-authorization by putting in an extra of any tenant data you need. You then perform an authorization request using the auth service and pass in the Pending Intent.

val pending = RootActivity.createSSOPostAuthorizationIntent(this, request)
    authService.performAuthorizationRequest(request, pending, tab)

Where my createSSOPostAuthorizationIntent is

        fun createSSOPostAuthorizationIntent(context: Context, request: AuthorizationRequest): PendingIntent {
            val intent = Intent(context, RootActivity::class.java)
            return if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
                PendingIntent.getActivity(context, request.hashCode(), intent, FLAG_MUTABLE)
            } else {
                PendingIntent.getActivity(context, request.hashCode(), intent, FLAG_UPDATE_CURRENT)
            }
        }

matthewbahr avatar Mar 10 '22 14:03 matthewbahr

Thanks, although it's not about the question. BTW Studio tells me the FLAG_MUTABLE is available from S (31) on, not R (30).

rwst avatar Mar 10 '22 15:03 rwst

Thanks updated.

The point though is that no part of the authentication process in 0.11.1 requires registration for activity result, so the deprecation doesn't matter?

matthewbahr avatar Mar 10 '22 15:03 matthewbahr

The code in appauthdemo uses it and loses therefore soon its reusability. Also the README suggests it as viable alternative which is misleading. Just removing the parts would make this ticket irrelevant, of course, but I don't know how the maintainers will decide. Until then I would like to keep this open.

rwst avatar Mar 11 '22 07:03 rwst

Totally agree that it could be changed, just providing code to answer your question of

What would be the equivalent that uses the recommended

It wouldn't hurt to make a pull request to update the readme.

matthewbahr avatar Mar 11 '22 12:03 matthewbahr

You can use:

  private val authorizationLauncher = registerLauncherResultAuthorization { result ->
    result.dataSuccess?.let {  }
    result.exception?.let { Timber.e(it) }
  }

  private val logoutLauncher = registerLauncherResultAuthorization { result ->
    result.dataSuccess?.let {  }
    result.exception?.let { Timber.e(it) }
  }
object OAuthLauncher {
  data class LauncherResult<T, E>(
    val dataSuccess: T,
    val exception: E
  )

  fun Fragment.registerLauncherResultAuthorization(
    onResult: (LauncherResult<AuthorizationResponse?, Throwable?>) -> Unit
  ) = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
  ) { result ->
    if (result.resultCode == Activity.RESULT_OK) {
      val res = AuthorizationResponse.fromIntent(result.data!!)
      val ex = AuthorizationException.fromIntent(result.data!!)

      onResult(LauncherResult(res, ex?.cause))
    } else {
      onResult(LauncherResult(null, Exception("Cancelled")))
    }
  }

  fun Fragment.registerLauncherResultLogout(
    onResult: (LauncherResult<EndSessionResponse?, Throwable?>) -> Unit
  ) = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
  ) { result ->
    if (result.resultCode == Activity.RESULT_OK) {
      val res = EndSessionResponse.fromIntent(result.data!!)
      val ex = AuthorizationException.fromIntent(result.data!!)

      onResult(LauncherResult(res, ex?.cause))
    } else {
      onResult(LauncherResult(null, Exception("Cancelled")))
    }
  }
}

Only need generate the intents and call by launchers defined on fragment or activity

I would send an update in Readme or code, but need to sign CLA. I believe that solves it issue! :)

joaoeudes7 avatar May 19 '22 12:05 joaoeudes7

Version 0.11.1 In Android 12, I have PendingIntent issue when call API login. I don't know why because I am not using PendingIntent

dattran-pt19 avatar Nov 17 '22 07:11 dattran-pt19

None of these work. Version 0.11.1. :(

intellitour avatar Jul 03 '23 14:07 intellitour

I have been struggling with this for the last two days. However, this project has successfully implemented it with v0.11.1: Clowning

I literally copy pasted the code into my project but still couldn't get it working. Probably has to do with the combination of versions of different dependencies?

Update: I got it working.

Here is what worked for me:

  • added this intent filter to the activity that has the login button
<intent-filter>
                <action android:name="com.example.yourproject.HANDLE_AUTHORIZATION_RESPONSE"/>
                <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
  • Removed the noHistory="true" option (or just set it to false)

That's it. It just worked. Here is my auth code:


    private val launcher = registerForActivityResult(StartActivityForResult()){
        if (it.resultCode == RESULT_OK) {
            val ex = AuthorizationException.fromIntent(it.data!!)
            val result = AuthorizationResponse.fromIntent(it.data!!)

            if (ex != null){
                Log.e("Github Auth", "launcher: $ex")
            } else {
                val secret = ClientSecretBasic(GITHUB_CLIENT_SECRET)
                val tokenRequest = result?.createTokenExchangeRequest()

                service.performTokenRequest(tokenRequest!!, secret) {res, exception ->
                    if (exception != null){
                        Log.e("Github Auth", "launcher: ${exception.error}" )
                    } else {
                        val token = res?.accessToken
                        viewModel.setToken(token!!)
                        // Move to Github screen
                        val intent = Intent(this, MainActivity::class.java)
                        startActivity(intent)
                        finish()
                    }
                }
            }
        }
    }

    private fun githubAuth() {
        val redirectUri = Uri.parse("com.example.yourproject://oauth2redirect")
        val authorizeUri = Uri.parse("https://github.com/login/oauth/authorize")
        val tokenUri = Uri.parse("https://github.com/login/oauth/access_token")

        val config = AuthorizationServiceConfiguration(authorizeUri, tokenUri)
        val request = AuthorizationRequest
            .Builder(config, GITHUB_CLIENT_ID, ResponseTypeValues.CODE, redirectUri)
            .setScopes("user repo admin")
            .build()

        val intent = service.getAuthorizationRequestIntent(request)
        launcher.launch(intent)
    }

This article was good help: https://medium.com/androiddevelopers/authenticating-on-android-with-the-appauth-library-7bea226555d5

amkhrjee avatar Jul 04 '23 15:07 amkhrjee