Keycloak is an open source Identity and Access Management solution aimed at modern applications and services. It makes it easy to secure applications and services with little to no code. It's open source and free to use
- When you don't know how to implement complex role based user authentication/ authorization mechanism to your app.
- Accelerated development time? maybe you'll have great business logic to focus on.
- Setup and deploy KeyCloak Server. ( In 5 Mins ?😎😎 )
- Setup Realms and Clients.
- Configure Android App with AeroGear
- Configure NodeJS App with KeyCloak
- Connect Android Client to NodeJS API
Yes, We do this on free stuff. only free stuff... 😁 https://elements.heroku.com/buttons/mieckert/keycloak-heroku visit this and you'll see a beautiful button to deploy Configure an app name, username and password, hit save.
Realm is like an application context, You'll have many types of clients inside a realm, like an api will serve angular application as well as an android client. all three components will be in a single realm.
- You'll notice a master realm that has been created for you
It is the highest level in the hierarchy of realms. Admin accounts in this realm have permissions to view and manage any other realm created on the server instance
- For our application, we'll create another realm
- Hover over "master" in sidebar panel ➡ click add realm ➡ type a name ➡ hit create
- In Realm settings ( Menu ) ➡ Goto Login tab ➡ tick User Registeration, Login With Email and click Save.
- In Clients ( Menu ), there will be serveal ClientIDs already created for you. click on account
- add "oauth://oauth2callback" 🤷♂️( This is for Android Client )
- change Access Type to Public
- click Save.
Dependancies build.gradle(Module: app)
implementation ('org.jboss.aerogear:aerogear-android-authz:2.0.0') {
exclude module : 'compatibility-v4'
transitive = true
}
Android Manifest.xml file
<uses-permission android:name="android.permission.INTERNET"/>
<service android:name="org.jboss.aerogear.android.authorization.oauth2.OAuth2AuthzService"/>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="oauth2callback"
android:scheme="oauth" />
</intent-filter>
</activity>
MainActivity.java ( onCreate )
try {
//Change -> testapp ( realm name ) and base URL
AuthorizationManager.config("KeyCloakAuthz", OAuth2AuthorizationConfiguration.class)
.setBaseURL(new URL("https://your-app-name.herokuapp.com/auth"))
.setClientId("account")
.setAuthzEndpoint("/realms/testapp/protocol/openid-connect/auth")
.setAccessTokenEndpoint("/realms/testapp/protocol/openid-connect/token")
.setRefreshEndpoint("/realms/testapp/protocol/openid-connect/token")
.setAccountId("account")
.setRedirectURL("oauth://oauth2callback")
.asModule();
PipeManager.config("kc-upload", RestfulPipeConfiguration.class)
.module(AuthorizationManager.getModule("KeyCloakAuthz"))
.requestBuilder(new MultipartRequestBuilder());
authzModule = AuthorizationManager.getModule("KeyCloakAuthz");
} catch (MalformedURLException e) {
e.printStackTrace();
}
Let's create a button in MainActivity.xml and bind login method to click event.
public void login(View view) {
authzModule.requestAccess(this, new Callback<String>() {
@Override
public void onSuccess(String s) {
//callback.onSuccess(s);
Log.d(TAG, "Bearer Token :" + s);
}
@Override
public void onFailure(Exception e) {
if (!e.getMessage().matches(OAuthWebViewDialog.OAuthReceiver.DISMISS_ERROR)) {
authzModule.deleteAccount();
}
}
});
}
{ Authorization : { Bearer XXXXX }
- Create a new client ➡ NodeAPI
- Access Type ➡ Public
- Valid Redirect URLs ➕ http://localhost:3000/*
- Goto Installation tab ➡ Select KeyCloak OIDC Json ➡ Download ( keycloak.json)
- npm init -y
- npm install express --save
- npm install express-session --save
- npm install keycloak-connect --save
const session = require("express-session");
const Keycloak = require("keycloak-connect");
const express = require("express");
const app = express();
// Configure session
var memoryStore = new session.MemoryStore();
var keycloak = new Keycloak({ store: memoryStore });
app.use(
session({
secret: "mySecret",
resave: false,
saveUninitialized: true,
store: memoryStore
})
);
// Attach middleware
app.use(keycloak.middleware());
app.get("/", (req, res, next) => {
res.json({ status: "Public Endpoint" });
});
app.get("/user/whoami", keycloak.protect(), (req, res, next) => {
console.log(req.kauth.grant.access_token.content);
let userinfo = {
name: req.kauth.grant.access_token.content.name,
email: req.kauth.grant.access_token.content.email,
};
res.json(userinfo);
});
app.listen(...) , you know this..
Open your browser and goto http://localhost:3000/user/whoami , you will be redirected to keycloak login, Create a new user and logIn to view user details as we implemented in Node route.
After a success login, android client will receive a JWT Token from authzModule.requestAccess(..) call, save this token in runtime and use Retrofit or equalent http client including header { Authorization : Bearer a8sjc9ec.. }
public interface UserService {
@GET("/user/whoami")
List<UserDetails> getUserDetails(@Header("Authorization") String bearerToken);
}
// BearerToken Should look like -> "Bearer WdNQ3dUQ..."
I wrote this article on my first attempt with KeyCloak server, See any antipatterns ? want to add more to this article? Let me know!
Cheers 🥂
add "oauth://oauth2callback" 🤷♂️( This is for Android Client )
--- Add where?