appauth android

Overview

AppAuth is a client SDK for native apps to authenticate and authorize end-users using OAuth 2.0 and OpenID Connect. Available for iOSmacOSAndroid, and Native JS environments, it implements modern security and usability best practices for native app authentication and authorization.

It strives to directly map the requests and responses of those specifications while following the idiomatic style of the implementation language. In addition to mapping the raw protocol flows, convenience methods are available to assist with common tasks like performing an action with fresh tokens.

Requirements

AppAuth supports Android API 16 (Jellybean) and above. Browsers which provide a custom tabs implementation are preferred by the library, but not required. Both Custom URI Schemes (all supported versions of Android) and App Links (Android M / API 23+) can be used with the library.

1. Add AppAuth as a Build Dependency

Add the following line to the build.gradle to the in the app directory. This will make the AppAuth library available to your project.

build.gradle

compile 'net.openid:appauth:0.2.0'

2. Create the ServiceConfiguration

First, AppAuth must be instructed on how to interact with the authorization service. This can be done either by directly creating an AuthorizationServiceConfiguration instance.

Directly specifying an AuthorizationServiceConfiguration involves providing the URIs of the authorization endpoint and token endpoint.

val serviceConfig = AuthorizationServiceConfiguration(
    Uri.parse("https://accounts.google.com/o/oauth2/v2/auth"), // authorization endpoint
    Uri.parse("https://www.googleapis.com/oauth2/v4/token") // token endpoint
)

3.Build the AuthorizationRequest

Once you have an instance of AuthorizationServiceConfiguration, you can now build an instance of AuthorizationRequest which describes actual authorization request, including your OAuth client id, and the scopes you are requesting.

val clientId = "511828570984-fuprh0cm7665emlne3rnf9pk34kkn86s.apps.googleusercontent.com"
val redirectUri = Uri.parse("com.google.codelabs.appauth:/oauth2callback")
val builder = AuthorizationRequest.Builder(
    serviceConfig,
    clientId,
    ResponseTypeValues.CODE,
    redirectUri
)
builder.setScopes("profile")

val authRequest = builder.build()

Be sure to register your own client ID when developing your own apps, and update the clientId and redirectUri values with your own (and the custom scheme registered in the AndroidManifest.xml). If using a different OAuth server, then you’ll need to register a client for that server, following their documentation.

 4. Perform the Authorization Request

a startActivityForResult call using an Intent returned from the AuthorizationService.

val authService = AuthorizationService(this)
val authIntent = authService.getAuthorizationRequestIntent(authRequest)
startActivityForResult(authIntent, RC_AUTH)

5. Handle the Authorization Response

Once the authorization flow is completed in the browser, the authorization service will redirect to a URI specified as part of the authorization request, providing the response via query parameters. In order for your app to capture this response, it must register with the Android OS as a handler for this redirect URI.

When a custom scheme is used, AppAuth can be easily configured to capture all redirects using this custom scheme through a manifest placeholder:

android.defaultConfig.manifestPlaceholders = [
  'appAuthRedirectScheme': 'com.example.app'
]

Alternatively, the redirect URI can be directly configured by adding an intent-filter for AppAuth’s RedirectUriReceiverActivity to your AndroidManifest.xml:

<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.google.codelabs.appauth"/>
    </intent-filter>
</activity>

If an HTTPS redirect URI is required instead of a custom scheme, the same approach (modifying your AndroidManifest.xml) is used:

<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="https"
              android:host="app.example.com" android:path="/oauth2redirect"/>
    </intent-filter>
</activity>

6. Handling the authorization response

Upon completion of the authorization flow, the completion Intent provided to performAuthorizationRequest will be triggered. The authorization response is provided to this activity via Intent extra data, which can be extracted using the fromIntent() methods on AuthorizationResponse and AuthorizationException respectively:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RC_AUTH) {
AuthorizationResponse resp = AuthorizationResponse.fromIntent(data);
AuthorizationException ex = AuthorizationException.fromIntent(data);
// … process the response or exception …
} else {
// …
}
}

7. Exchanging the authorization code

Given a successful authorization response carrying an authorization code, a token request can be made to exchange the code for a refresh token:

mAuthService?.performTokenRequest(
    resp.createTokenExchangeRequest()) { resp, ex ->
    if (resp != null) {
        mStateManager?.updateAfterTokenResponse(resp, ex)

        Log.d("accessToken",resp.accessToken)

        // exchange succeeded
    } else {
        // authorization failed, check ex for more details
    }
}

That’s it. We got an access token to access our API.

Final Code,

class LoginActivity : AppCompatActivity() {
    private val RC_AUTH = 100

    private var mAuthService: AuthorizationService? = null
    private var mStateManager: AuthStateManager? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.login_activity)

        mStateManager = AuthStateManager.getInstance(this)

        if(mStateManager?.current?.isAuthorized!!) {
            Log.d("Auth","Done")
        }

        button_login.setOnClickListener {
            val serviceConfig = AuthorizationServiceConfiguration(
                Uri.parse("https://accounts.google.com/o/oauth2/v2/auth"), // authorization endpoint
                Uri.parse("https://www.googleapis.com/oauth2/v4/token") // token endpoint
            )

            mAuthService = AuthorizationService(this)
            val clientId = "511828570984-fuprh0cm7665emlne3rnf9pk34kkn86s.apps.googleusercontent.com"
            val redirectUri = Uri.parse("com.google.codelabs.appauth:/oauth2callback")
            val builder = AuthorizationRequest.Builder(
                serviceConfig,
                clientId,
                ResponseTypeValues.CODE,
                redirectUri
            )
            builder.setScopes("profile")

            val authRequest = builder.build()


          /*  val intentBuilder = mAuthService?.createCustomTabsIntentBuilder(authRequest.toUri())
            intentBuilder?.setToolbarColor(ContextCompat.getColor(this, R.color.colorAccent))
            customIntent = intentBuilder?.build()*/

            val authService = AuthorizationService(this)
            val authIntent = authService.getAuthorizationRequestIntent(authRequest)
            startActivityForResult(authIntent, RC_AUTH)
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        if (requestCode == RC_AUTH) {
            val resp = AuthorizationResponse.fromIntent(data!!)
            val ex = AuthorizationException.fromIntent(data)

            if (resp != null) {
                mAuthService = AuthorizationService(this)
                mStateManager?.updateAfterAuthorization(resp,ex)

                mAuthService?.performTokenRequest(
                    resp.createTokenExchangeRequest()) { resp, ex ->
                    if (resp != null) {
                        mStateManager?.updateAfterTokenResponse(resp, ex)

                        Log.d("accessToken",resp.accessToken)

                        // exchange succeeded
                    } else {
                        // authorization failed, check ex for more details
                    }
                }

                //Log.d("res",resp.accessToken)
                // authorization completed
            } else {
                // authorization failed, check ex for more details
            }
            // ... process the response or exception ...
        } else {
            // ...
        }
    }
}

Download the code on Github,

github_link

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to Top
%d bloggers like this: