8

I need to add OAuth2 authorization in my app. I have only client-id, client-secret and username(email). I need to get token. Can you give me some advise on how to do that? Library or example code?

1 Answer 1

16

You can use AppAuth to do a OAuth2 authorization.

See https://github.com/openid/AppAuth-Android for a example.


The following is a shortend version of the AppAuth documentation.

Overview

It is recommended that native apps use the authorization code flow.

This flow is effectively composed of four stages:

  1. Specifying the authorization service configuration.
  2. Authorizing via a browser, in order to obtain an authorization code.
  3. Exchanging the authorization code, to obtain an access and refresh token.
  4. Using the access token to access protected resource service.

1. Create authorization service configuration

First, create a configuration of the authorization service, which will be used in stage two and three.

AuthorizationServiceConfiguration mServiceConfiguration =
    new AuthorizationServiceConfiguration(
        Uri.parse("https://example.com/authorize"), // Authorization endpoint
        Uri.parse("https://example.com/token")); // Token endpoint

ClientAuthentication mClientAuthentication =
    new ClientSecretBasic("my-client-secret"); // Client secret

(Static client secrets aren't recommended in native apps.)

2. Request authorization and obtain authorization code

To receive the authorization callback define following activity in your manifest file. (You don't need to implement this activity. This activity will act like a proxy for your authorization request.)

<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.example"/> <!-- Redirect URI scheme -->
    </intent-filter>
</activity>

Build and execute the authorization request.

private void authorize() {
    AuthorizationRequest authRequest = new AuthorizationRequest.Builder(
        mServiceConfiguration,
        "my-client-id", // Client ID
        ResponseTypeValues.CODE,
        Uri.parse("com.example://oauth-callback") // Redirect URI
    ).build();

    AuthorizationService service = new AuthorizationService(this);

    Intent intent = service.getAuthorizationRequestIntent(authRequest);
    startActivityForResult(intent, REQUEST_CODE_AUTH);
}

Handle the authorization response.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    if (requestCode != REQUEST_CODE_AUTH) {
        return;
    }

    AuthorizationResponse authResponse = AuthorizationResponse.fromIntent(intent);
    AuthorizationException authException = AuthorizationException.fromIntent(intent);

    mAuthState = new AuthState(authResponse, authException);

    // Handle authorization response error here

    retrieveTokens(authResponse);
}

3. Exchange the authorization code

private void retrieveTokens(AuthorizationResponse authResponse) {
    TokenRequest tokenRequest = response.createTokenExchangeRequest();

    AuthorizationService service = new AuthorizationService(this);

    service.performTokenRequest(request, mClientAuthentication,
            new AuthorizationService.TokenResponseCallback() {
        @Override
        public void onTokenRequestCompleted(TokenResponse tokenResponse,
                AuthorizationException tokenException) {
            mAuthState.update(tokenResponse, tokenException);

            // Handle token response error here

            persistAuthState(mAuthState);
        }
    });
}

After the token retrieval was completed successfully, persist AuthState so you can reuse it at the next app (re)start.

4. Access protected resource service

Use performActionWithFreshTokens to execute the API call with a fresh access token. (It will automatically ensure that the tokens are fresh and refresh them when needed.)

private void prepareApiCall() {
    AuthorizationService service = new AuthorizationService(this);

    mAuthState.performActionWithFreshTokens(service, mClientAuthentication,
            new AuthState.AuthStateAction() {
        @Override
        public void execute(String accessToken, String idToken,
                AuthorizationException authException) {
            // Handle token refresh error here

            executeApiCall(accessToken);
        }
    });
}

Execute the API call. (The AsyncTask is just use for simplicity. It might not be the best solution to execute the API call.)

private void executeApiCall(String accessToken) {
    new AsyncTask<String, Void, String>() {
        @Override
        protected String doInBackground(String... params) {
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    .url("https://example.com/api/...") // API URL
                    .addHeader("Authorization",
                            String.format("Bearer %s", params[0]))
                    .build();

            try {
                Response response = client.newCall(request).execute();
                return response.body().string();
            } catch (Exception e) {
                // Handle API error here
            }
        }

        @Override
        protected void onPostExecute(String response) {
            ...
        }
    }.execute(accessToken);
}
Sign up to request clarification or add additional context in comments.

2 Comments

Is this the recommended approach for Android? I used to think mobile devices can use the device's default web browser as a user agent to handle code & token redirection. Has this changed recently?
AppAuth is recommended by Google. It uses Chrome Custom Tabs for the authorization request. Chrome Custom Tabs have some advantages over the device's default web browser. For example, the Custom Tab overlaps the last shown Activty. (See following talk from Google: youtu.be/DdQTXrk6YTk?t=220)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.