Android Code Sample – Infrastructure

Background

Previously we described How to Run the Android Code Sample, and next we will focus further on the infrastructure used by our OAuth solution.

AWS CloudFront Domains

Our Android sample uses 2 online domains, which we configured previously as part of our Cloud Domain Setup:

Domain Usage
mobile.authsamples.com The domain name for mobile deep linking, which points to a cloud location that hosts deep linking assets
authsamples.com We use the root domain for ad-hoc hosting of simple web pages, including interstitial Post Login / Logout web pages

Interstitial Web Page Hosting

Our web pages are first uploaded to an AWS S3 bucket:

They are then included in one of this blog’s CloudFront Distributions, so that the pages are served over an HTTPS URL:

Pages are then available at these URLs:

Deep Linking Assets File

In order for claimed HTTPS scheme logins to work you must configure Android app link verification. This includes hosting a deep linking assets file, which is contained in the project at security/assetlinks.json. This associates our app’s signing key and package name with its hosting domain:

[
  {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
      "namespace": "android_app",
      "package_name": "com.authsamples.basicmobileapp",
      "sha256_cert_fingerprints":
      ["62:7D:06:B1:01:C6:2F:04:9A:D4:5D:17:DF:FF:AB:65:13:8E:E0:CC:F6:60:2A:F6:3A:DA:1D:19:0A:F9:DF:15"]
    }
  }
]

The deep linking domains allowed by the app are configured with an https scheme in the manifest file:

<activity
    android:name=".plumbing.oauth.logout.LogoutRedirectUriReceiverActivity"
    android:exported="true">

    <intent-filter android:autoVerify="true">
        <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="mobile.authsamples.com"
            android:path="/basicmobileapp/oauth/logoutcallback" />
    </intent-filter>
</activity>

I uploaded the assets file to run at the below HTTPS URL, in a similar manner to the interstitial pages. We use a second S3 bucket and Cloudfront distribution for the root domain:

The mobile.authsamples.com S3 bucket has a .well-known folder containing the assets files for both Android and iOS:

Deep Linking Online Verification

We can verify the assets file via a test site that Google provides, and check that results do not contain any errors:

Deep Linking Registration Process

When our app is installed, deep linking registration is done via system components, as described via this article on Android App Links.

To understand how this works, uninstall the app, then re-run it while viewing the logcat window. Filter on the word Verification and ensure that the No Filters option is selected:

Once we have run the app we can execute the following command to query its deep linking verification status:

adb shell pm get-app-links com.authsamples.basicmobileapp

This should return a domain verification state of ‘verified‘:

com.authsamples.basicmobileapp:
    ID: 241b4727-f96d-40ad-8459-8238c0fb8747
    Signatures: [62:7D:06:B1:01:C6:2F:04:9A:D4:5D:17:DF:FF:AB:65:13:8E:E0:CC:F6:60:2A:F6:3A:DA:1D:19:0A:F9:DF:15]
    Domain verification state:
      mobile.authsamples.com: verified

Deep Linking Registration Failures

Deep linking registration can fail, and one way to reproduce this is to configure the mobile device to connect to the internet via an HTTP Proxy:

The system’s Intent Filter Verifier will not trust the HTTP proxy’s man in the middle certificate, and the result is that the app installs successfully but the Claimed HTTPS Scheme is not correctly configured:

We can then re-run the command to query the status of our app and the result will now use a domain verification state of ‘none‘:

com.authsamples.basicmobileapp:
    ID: 241b4727-f96d-40ad-8459-8238c0fb8747
    Signatures: [62:7D:06:B1:01:C6:2F:04:9A:D4:5D:17:DF:FF:AB:65:13:8E:E0:CC:F6:60:2A:F6:3A:DA:1D:19:0A:F9:DF:15]
    Domain verification state:
      mobile.authsamples.com: none

We can then run a deep link to our app on an emulator, via a command such as this:

adb shell am start -a android.intent.action.VIEW -d https://mobile.authsamples.com/basicmobileapp/deeplink/company/2

This will result in the following undesired behaviour, where the system browser attempts to open the URL, rather than the mobile app:

HTTP Debugging and Claimed HTTPS Schemes

During development, I use an HTTP proxy as follows when I want to view OAuth or API messages for the Android app. The mobile OS only registers App Links when the app is first installed, and not when it is redeployed from Android Studio:

  • First install the app without using an HTTP proxy
  • Deep linking registration will then succeed
  • Start the HTTP Proxy on the host PC
  • Next configure the Android emulator to use the HTTP Proxy
  • Then redeploy the app from Android Studio
  • Messages from the app will then be captured successfully

Android App Code Signing

To finish off our discussion on Deep Linking, let’s look at how I generated the signature from the assets file. Install the Java KeyStore Explorer and open our KeyStore file, which has a password of ‘android‘:

For educational purposes I have included the keystore file with my source code, though of course you should not do this for a real app. I then used the Tools / Generate Key Pair option to create an RSA key with default options and a 10 year validity:

I then chose Add Extensions / Use Standard Template / Code Signing and included the Subject Key Identifier extension:

I then used some naming to fit with this blog, and copied the below SHA256 Fingerprint to the mobile assets file:

Finally, the app’s gradle file references our Android Keystore File, which is used to digitally sign our app when it is built.

signingConfigs {
    release {
        storeFile file("${rootDir}/security/app-keystore.jks")
        storePassword "android"
        keyAlias "com.authsamples.basicmobileapp"
        keyPassword "android"
    }
}

buildTypes {
    debug {
        signingConfig signingConfigs.release
        debuggable true
    }
    release {
        signingConfig signingConfigs.release
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}

When the app is deployed to the device, the Intent Filter Verifier can verify that the key in the Cloud Assets JSON Document matches the key used to digitally sign the mobile app.

Where Are We?

We have explained some infrastructure plumbing needed for our Android code sample. Using claimed HTTPS schemes for mobile logins required some interaction between the mobile device and cloud endpoints.

Next Steps