AppAuth for Android

repository·master·Indexed 25 days ago

https://github.com/openid/appauth-android

A client SDK for communicating with OAuth 2.0 and OpenID Connect providers. It follows RFC 8252 best practices for native apps by utilizing Custom Tabs instead of WebViews. The library provides core classes such as AuthState for session persistence, AuthorizationService for server communication, and utilities for managing authorization requests, token exchange, and end-session flows. It supports Android API 16 and above.

Tokens
7.5K
Snippets
18
Records
23
Agent score
85%

What's inside AppAuth for Android

  1. AppAuth for Android Requirements

    master

    To use AppAuth, ensure your project meets the following requirements:

    • Android API Level: Supports API 16 (Jellybean) and above.
    • Browser Support: Prefers browsers that implement Custom Tabs (though not strictly required).
    • Redirect Mechanisms: Supports both Custom URI Schemes (all Android versions) and App Links (Android M / API 23+).
    • Authorization Server Compatibility: Works with any Authorization Server (AS) following RFC 8252. Note that servers requiring client secrets for confidentiality or assuming web-only clients may not be compatible.
  2. Conceptual Overview of AppAuth

    master

    AppAuth manages OAuth 2.0 and OpenID Connect flows using several core classes:

    • AuthState: Encapsulates the user's authorization state. It is designed to be easily persistable as a JSON string using your preferred storage (e.g., SharedPreferences, sqlite, or files).
    • AuthorizationService: The primary class used to communicate with the authorization server. It dispatches requests like performAuthorizationRequest() and performTokenRequest().
    • AuthorizationRequest: Models the authorization request sent to the user's web browser.
    • AuthorizationResponse: The result of an authorization request, typically dispatched to an Activity via an Intent.
    • TokenRequest & TokenResponse: Used for token-related operations (like refreshing tokens). TokenRequest is dispatched via AuthorizationService, and TokenResponse is returned via a callback.

    Key Workflow Pattern: Use AuthState.update() to track and persist changes to the authorization state. Once authorized, use AuthState.performActionWithFreshTokens() to automatically refresh access tokens before performing actions that require valid tokens.

  3. Configure Authorization Service

    master

    To interact with an identity provider (IDP), you must first configure an AuthorizationServiceConfiguration. You can either manually specify the endpoints or use OpenID Connect discovery, which is the preferred method.

    Manual Configuration: Provide the authorization and token URIs directly.

    Discovery (Recommended): Use fetchFromIssuer to automatically download the configuration from the standard .well-known/openid-configuration endpoint, or fetchFromUrl if the discovery document is at a non-standard location.

    // Manual specification
    AuthorizationServiceConfiguration serviceConfig =
        new AuthorizationServiceConfiguration(
            Uri.parse("https://idp.example.com/auth"),
            Uri.parse("https://idp.example.com/token"));
    
    // Discovery from Issuer
    AuthorizationServiceConfiguration.fetchFromIssuer(
        Uri.parse("https://idp.example.com"),
        new AuthorizationServiceConfiguration.RetrieveConfigurationCallback() {
          public void onFetchConfigurationCompleted(
              @Nullable AuthorizationServiceConfiguration serviceConfiguration,
              @Nullable AuthorizationException ex) {
            if (ex != null) {
              // handle error
              return;
            }
            // use serviceConfiguration
          }
        }
    );
    
    // Discovery from specific URL
    AuthorizationServiceConfiguration.fetchFromUrl(
        Uri.parse("https://idp.example.com/exampletenant/openid-config"),
        new AuthorizationServiceConfiguration.RetrieveConfigurationCallback() {
            // ...
        }
    });
  4. Use Access Tokens with AuthState

    master

    Instead of manually managing tokens, use AuthState.performActionWithFreshTokens. This utility method automatically handles token refreshing if the current access token is expired. The provided callback gives you the fresh accessToken and idToken to use for your resource server requests.

    authState.performActionWithFreshTokens(service, new AuthStateAction() {
      @Override public void execute(
          String accessToken,
          String idToken,
          AuthorizationException ex) {
        if (ex != null) {
          // handle error
          return;
        }
        // use the access token to interact with resource server
      }
    });
  5. Obtain an Authorization Code

    master

    Construct an AuthorizationRequest using its Builder. Mandatory parameters include the AuthorizationServiceConfiguration, client_id, response_type (use ResponseTypeValues.CODE), and the redirect_uri. You can optionally set scopes or a login hint.

    To dispatch the request, you can either:

    1. Use AuthorizationService.getAuthorizationRequestIntent(authRequest) and call startActivityForResult (simpler, requires manual result processing).
    2. Use AuthorizationService.performAuthorizationRequest(...) to provide PendingIntents for completion and cancellation handling (allows direct activity transitions).
    // 1. Build the request
    AuthorizationRequest.Builder authRequestBuilder =
        new AuthorizationRequest.Builder(
            serviceConfig,
            MY_CLIENT_ID,
            ResponseTypeValues.CODE,
            MY_REDIRECT_URI);
    
    AuthorizationRequest authRequest = authRequestBuilder
        .setScope("openid email profile")
        .setLoginHint("jdoe@user.example.com")
        .build();
    
    // 2. Dispatch via startActivityForResult
    AuthorizationService authService = new AuthorizationService(this);
    Intent authIntent = authService.getAuthorizationRequestIntent(authRequest);
    startActivityForResult(authIntent, RC_AUTH);
    
    // 3. Handle result in onActivityResult
    @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 resp or ex
      }
    }
  6. End User Session

    master

    To log a user out, build an EndSessionRequest using the AuthorizationServiceConfiguration, the user's idToken (as a hint), and a post-logout redirect URI. You can dispatch this request using startActivityForResult or performEndSessionRequest.

    EndSessionRequest endSessionRequest =
        new EndSessionRequest.Builder(authorizationServiceConfiguration)
            .setIdTokenHint(idToken)
            .setPostLogoutRedirectUri(endSessionRedirectUri)
            .build();
    
    // Dispatch via performEndSessionRequest
    AuthorizationService authService = new AuthorizationService(this);
    authService.performEndSessionRequest(
        endSessionRequest,
        PendingIntent.getActivity(this, 0, new Intent(this, MyAuthCompleteActivity.class), 0),
        PendingIntent.getActivity(this, 0, new Intent(this, MyAuthCanceledActivity.class), 0));
  7. Configure an OpenID Client on Gluu Server

    master

    To use AppAuth with Gluu, you must first register a client on your Gluu server.

    1. Navigate to https://{{Your_gluu_server_domain}}/identity/client/inventory and select Add Client.
    2. Enter required fields: Client Name, Client Secret, Application Type, Pre-Authorization, Persist Client Authorizations, and Logout Session Required.
    3. Set Application Type to Native or web.
    4. Click Add Grant type and select Authorization Code.
    5. Set your Redirect URIs using a custom scheme, e.g., appscheme://client.example.com.
    6. Important Security Setting: Set Authentication method for the Token Endpoint to none. This avoids the need to store a client_secret in your Android application, which is not recommended for security reasons.
    7. Copy the generated Client ID for use in your Android project.
  8. Exchange Authorization Code for Tokens

    master

    Once you have a successful AuthorizationResponse containing an authorization code, use AuthorizationService.performTokenRequest to exchange it for tokens (e.g., access token, refresh token).

    authService.performTokenRequest(
        resp.createTokenExchangeRequest(),
        new AuthorizationService.TokenResponseCallback() {
          @Override public void onTokenRequestCompleted(
                TokenResponse resp, AuthorizationException ex) {
            if (resp != null) {
              // exchange succeeded
            } else {
              // handle error
            }
          }
        });
  9. Perform dynamic client registration

    master

    AppAuth supports the OAuth2 dynamic client registration protocol (RFC 7591). To register a client, create a RegistrationRequest and dispatch it via AuthorizationService.performRegistrationRequest. The registration endpoint can be part of your AuthorizationServiceConfiguration or discovered via OIDC discovery.

    RegistrationRequest registrationRequest = new RegistrationRequest.Builder(
        serviceConfig,
        Arrays.asList(redirectUri))
        .build();
    
    service.performRegistrationRequest(
        registrationRequest,
        new AuthorizationService.RegistrationResponseCallback() {
            @Override public void onRegistrationRequestCompleted(
                @Nullable RegistrationResponse resp,
                @Nullable AuthorizationException ex) {
                if (resp != null) {
                    // registration succeeded, store the registration response
                    AuthState state = new AuthState(resp);
                } else {
                  // registration failed, check ex for more details
                }
             }
        });
  10. Build AppAuth for Android from command line

    master

    AppAuth uses Gradle. To build the library and demo app, or to run tests, use the following commands:

    • Build binaries: ./gradlew assemble (AARs in library/build/outputs/aar, APKs in app/build/outputs/apk).
    • Run tests and analysis: ./gradlew check.
    ./gradlew assemble
    ./gradlew check
  11. Configure Google Sign-In with AppAuth for Android

    master

    To use AppAuth with Google Sign-In, you must create an OAuth2 client ID in the Google Developer Console and configure your Android project with the resulting credentials and redirect URI scheme.

    1. Obtain your SHA-1 fingerprint

    You need the SHA-1 fingerprint of the certificate used to sign your app. If you are using the provided appauth.keystore, you can extract the SHA-1 signature using keytool:

    keytool -list -v -keystore appauth.keystore -storepass appauth | \
        grep SHA1\: | \
        awk '{print $2}'

    2. Configure auth_config.json

    Create or update your auth_config.json file with your Google client ID. The redirect_uri must follow the pattern com.googleusercontent.apps.PREFIX:/oauth2redirect, where PREFIX is the alphanumeric string from your client ID.

    {
      "client_id": "PREFIX.apps.googleusercontent.com",
      "redirect_uri": "com.googleusercontent.apps.PREFIX:/oauth2redirect",
      "authorization_scope": "openid email profile",
      "discovery_uri": "https://accounts.google.com/.well-known/openid-configuration"
    }

    3. Update Android Manifest Redirect Scheme

    In your module-level build.gradle file, replace the appAuthRedirectScheme placeholder with your specific Google client prefix (e.g., com.googleusercontent.apps.PREFIX).

    4. Install the app

    Build and install the app to test the integration:

    ./gradlew :app:installDebug