2

I have been struggling a fair bit for a few days trying implementing an authentication flow with AppAuth Android and IdentityServer4 within an aspnet core api.

What I've managed to attain so far is

  1. Create what I think is necessary server side and tested this with Postman
  2. Manage to get AppAuth to open a tab where I sign in (however the successful sign in doesn't get sent back to the application)

Here are the client properties server side:

                new Client
                {
                    ClientId = "postman",
                    ClientName = "Postman Client",
                    AllowedGrantTypes = IdentityServer4.Models.GrantTypes.Code,

                    ClientSecrets =
                    {
                        new Secret("secret".Sha256())
                    },
                    RequireConsent = false,
                    RedirectUris = { "com.example.poc.appauth://callback" },
                    AllowedCorsOrigins = { "http://localhost:4300" },

                    AllowAccessTokensViaBrowser = true,
                    Enabled = true,
                    ClientUri = null,

                    AllowedScopes =
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        "api1"
                    },
                    AllowOfflineAccess = true
                },

And this client can be accessed from postman and tokens received.

Well, to the fun part where I bet I'm doing something wrong (even though I have read all three examples I could find..) - the configuration of Android client.

    build.gradle:

        android {
            compileSdkVersion 27

        lintOptions {
            disable 'InvalidPackage'
        }

        defaultConfig {
            // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.poc"
        minSdkVersion 16
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        manifestPlaceholders = ['appAuthRedirectScheme': 'com.example.poc.appauth']
    }

        dependencies {
            ...
            implementation 'net.openid:appauth:0.7.0'
        }

Where the changes I've added are

implementation 'net.openid:appauth:0.7.0'

and

manifestPlaceholders = ['appAuthRedirectScheme': 'com.example.poc.appauth']

Then I added some things in the the manifest (The complete manifest is added here):

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.poc">

<uses-permission android:name="android.permission.INTERNET"/>

<application
    android:name="io.flutter.app.FlutterApplication"
    android:label="poc"
    android:icon="@mipmap/ic_launcher">
    <activity
        android:name=".MainActivity"
        android:launchMode="singleTop"
        android:theme="@style/LaunchTheme"
        android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
        android:hardwareAccelerated="true"
        android:windowSoftInputMode="adjustResize">
        <meta-data
            android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
            android:value="true" />
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
        <intent-filter>
            <action android:name="com.example.poc.appauth.HANDLE_AUTHORIZATION_RESPONSE"/>
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
    </activity>

    <activity android:name="net.openid.appauth.RedirectUriReceiverActivity">
        <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.poc.appauth"/>
        </intent-filter>
    </activity>

</application>

For now I've added all the authorization implementations directly in MainActivity.

  private static final String AUTHORIZATION_ENDPOINT = "http://10.0.2.2:63692/account/login";
  private static final String TOKEN_ENDPOINT = "http://10.0.2.2:63692/connect/token";
  /* I have also tried
  private static final String REDIRECT_URI = "com.example.poc.appauth://callback";
  */
  private static final String REDIRECT_URI = "com.example.poc.appauth";
  private static final String CLIENT_ID = "postman";
  private static final String CLIENT_SECRET = "secret";
  private static final String SCOPE = "openid";
  private static final String RESPONSE_TYPE = "code";
  private static final String HANDLE_AUTH_RESPONSE = "com.example.poc.appauth.HANDLE_AUTHORIZATION_RESPONSE";

At startup of application I call authorize()

private void authorize() {
    AuthorizationServiceConfiguration serviceConfiguration = new AuthorizationServiceConfiguration(
            Uri.parse(AUTHORIZATION_ENDPOINT),
            Uri.parse(TOKEN_ENDPOINT)
    );

    AuthorizationRequest.Builder builder = new AuthorizationRequest.Builder(
            serviceConfiguration,
            CLIENT_ID,
            RESPONSE_TYPE,
            Uri.parse(REDIRECT_URI)
    );
    builder.setScopes(SCOPE);

    AuthorizationRequest request = builder.build();

    Intent postAuthorizationIntent  = new Intent(HANDLE_AUTH_RESPONSE);
    PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), request.hashCode(), postAuthorizationIntent , 0);

    _authService.performAuthorizationRequest(request, pendingIntent);
}

The login screen is opened in a tab and I can add my credentials and sign in (now I get redirected to the home-page within the browser tab).

I expect this function to be invoked when the login completes but it doesn't seem that way.

@Override
  protected void onNewIntent(Intent intent) {
    /* I've never reached this point. */
    Log.d(LOG_TAG, "New intent received");
    if (intent != null) {
      String action = intent.getAction();
      switch (action) {
        case HANDLE_AUTH_RESPONSE:
          if (!intent.hasExtra(USED_INTENT)) {
            handleAuthorizationResponse(intent);
            intent.putExtra(USED_INTENT, true);
          }
          break;
        default:
          // do nothing
      }
    }
  }

I'm sorry if this is too big of a question to ask, but I just can seem to find the errors within the configuration / implementation.

What I expect to happen is:

1) Application starts and a tab is opened with the login screen 2) I sign in and the custom tab is closed since I get redirected to my redirection-URI which the MainActivity should take care of and I get the postAuthorizationIntent.

Alex
  • 487
  • 1
  • 6
  • 19
  • Why do you want a return url? Why don't you just use resource owner password grandtype instead? That way, when login succeeds, you will just receive a token and know the user is logged in, – alsami Jul 29 '18 at 15:09
  • @als If that is a possibility it would be great, but all examples I've read uses the "deep link"-redirection (I think that's the name for it). The resource owner password type, is that the pkce and would that require the custom tab? Sorry for all the questions - this is somewhat very new to me. – Alex Jul 29 '18 at 15:13
  • No, it is just an oauth grant-type that is commonly used for cases where a client needs to authenticate. http://docs.identityserver.io/en/release/topics/resource_owner.html – alsami Jul 29 '18 at 15:17
  • Looking into that one now, it surely is easier to get it up and running... However, how secure is this flow? I mean, I have to send the username and password in the login request directly from the app. Is it only the https that will protect the credentials? – Alex Jul 29 '18 at 16:08
  • Yes, https will secure that case. While testing running on http is just fine. No worries, we've all been there. – alsami Jul 29 '18 at 16:14
  • Great, thank you alsami, I will resort to using the resource owner flow and use the refresh token to get new access tokens on a frequent basis so that I have to send the password as few times as possible :) – Alex Jul 29 '18 at 16:28
  • You can also use sliding expiration for your token. Everytime the user does a request the token expiration will be refreshed. Refreshtoken is for when token is completely expired. – alsami Jul 29 '18 at 16:29

0 Answers0