Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do oAuth with Keycloak OpenId in Android Client

I want to authenticate a user (using his username and password) in an Android App using aerogear with a server using Keycloak. I haven't been able to do it, help me please.

I currently can authenticate the user without aerogear, but I want to use this library since it can help me to refresh the token when is needed. I authenticate the user making a POST call to the server like this (but from android):

 curl -X POST http://127.0.0.1:8080/auth/realms/example/protocol/openid-connect/token  
 -H "Content-Type: application/x-www-form-urlencoded" -d "username=auser" -d 'password=apassword' -d 'grant_type=password' 
 -d 'client_id=clientId' -d 'client_secret=secret'

So the information I have is:

  • Authentication URL, ie http://127.0.0.1:8080/auth/realms/example/protocol/openid-connect/token
  • username, the username of the user
  • password, the password of the user
  • client_id, and client_secret of the Keycloak server

What I have tried with Aerogear is this:

private void authz() {
    try {

        AuthzModule authzModule = AuthorizationManager.config("KeyCloakAuthz", OAuth2AuthorizationConfiguration.class)
                .setBaseURL(new URL("http://127.0.0.1:8080/"))
                .setAuthzEndpoint("/realms/example/protocol/openid-connect/auth")
                .setAccessTokenEndpoint("/realms/example/protocol/openid-connect/token")
                .setAccountId("keycloak-token")
                .setClientId("clientId")
                .setClientSecret("secret")
                .setRedirectURL("http://oauth2callback")
                .setScopes(Arrays.asList("openid"))
                .addAdditionalAuthorizationParam((Pair.create("grant_type", "password")))
                .addAdditionalAuthorizationParam((Pair.create("username", "aUserName")))
                .addAdditionalAuthorizationParam((Pair.create("password", "aPassword")))
                .asModule();


        authzModule.requestAccess(this, new Callback<String>() {
            @Override
            public void onSuccess(String o) {
                Log.d("TOKEN ", o);
            }

            @Override
            public void onFailure(Exception e) {
                System.err.println("Error!!");
                Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
            }
        });

    } catch (Exception e) {

        e.printStackTrace();
        throw new RuntimeException(e);
    }
}

However this doesn't do anything. What I don't understand is:

  1. How can I specify that I'm doing and OpenID Connect with Keycloak in Aerogear?
  2. How and where can I send the username and password?
  3. How can I specify the grant_type? (My HTTP POST to the server does not work if I don't include this, so it's important)

Any help would be very much appreciated

like image 512
ACBM Avatar asked Oct 11 '16 21:10

ACBM


People also ask

Does Keycloak support OpenID?

Keycloak supports both OpenID Connect (an extension to OAuth 2.0) and SAML 2.0.

Does Keycloak support OAuth2?

Keycloak is Open Source Identity and Access Management Server, which is a OAuth2 and OpenID Connect(OIDC) protocol complaint.

How do you use an authentication Keycloak?

Configure Keycloak to authenticate your cbioportal instance. Log in to your Keycloak Identity Provider, e.g. http://localhost:8080/auth, as an admin user. ⚠️ when setting this up on something else than localhost (e.g. production), you will need to use/enable https on your Keycloak server.

How do I create a new OAuth client application in Keycloak?

To create a new OAuth Client application in Keycloak, you will need to login to the Keycloak server and select the Realm for which the client application needs to be created. To learn how to create new Keycloak users and a new Realm, please check the following tutorial: Creating a new Keycloak user and a new Realm.

Does Keycloak include the refresh token in the OAuth response?

If all is good with the request and the client credentials get successfully validated by the authorization server, the authorization server will respond back with an access token right away. According to OAuth 2.0 specs, the Refresh Token should not be included in the response. But apparently, Keycloak does include the refresh token anyways.

How do I enable the client credentials grant flow in Keycloak?

To enable the Client Credentials Grant flow for the OAuth client application in Keycloak, follow these steps: 1 Open the Client application, 2 Select the Settings tab, 3 Enable the Service Accounts as it is shown in the image below, 4 Click on the Save button. More ...

How to find client_ID and client_secret values for your OAuth client application?

Follow the below steps to find the client_id and the client_secret values for your OAuth client application in Keycloak. Open the Client application details in Keycloak, Switch to Credentials tab, Copy the Client Secret value. You will find the Client Id value on the Settings tab.


1 Answers

If you go with the standard Authorization Code flow with access type = public client (no clientSecret) then you may take a look at my example Android native app.

In short, you could open up a browser window in a WebView, get the authorization code by parsing the query parameter from the returned url and exchange it (the code) for the token via a POST request.

If you use Retrofit, then here is the REST interface:

interface IKeycloakRest {
    @POST("token")
    @FormUrlEncoded
    fun grantNewAccessToken(
        @Field("code")         code: String,
        @Field("client_id")    clientId: String,
        @Field("redirect_uri") uri: String,
        @Field("grant_type")   grantType: String = "authorization_code"
    ): Observable<KeycloakToken>

    @POST("token")
    @FormUrlEncoded
    fun refreshAccessToken(
        @Field("refresh_token") refreshToken: String,
        @Field("client_id")     clientId: String,
        @Field("grant_type")    grantType: String = "refresh_token"
    ): Observable<KeycloakToken>

    @POST("logout")
    @FormUrlEncoded
    fun logout(
        @Field("client_id")     clientId: String,
        @Field("refresh_token") refreshToken: String
    ): Completable
}

data class KeycloakToken(
    @SerializedName("access_token")       var accessToken: String? = null,
    @SerializedName("expires_in")         var expiresIn: Int? = null,
    @SerializedName("refresh_expires_in") var refreshExpiresIn: Int? = null,
    @SerializedName("refresh_token")      var refreshToken: String? = null
)

And its instantiation:

val rest: IKeycloakRest = Retrofit.Builder()
            .baseUrl("https://[KEYCLOAK-URL]/auth/realms/[REALM]/protocol/openid-connect/")
            .addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create()))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build()
            .create(IKeycloakRest::class.java)
like image 124
maslick Avatar answered Feb 06 '23 04:02

maslick