Augusto Picciani
Augusto Picciani

Reputation: 804

How to implement OAuth2 authorization on Android

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?

Upvotes: 8

Views: 18050

Answers (1)

Matt Ke
Matt Ke

Reputation: 3739

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);
}

Upvotes: 15

Related Questions