Step-by-step guide how integrate Keycloak with Angular application

If you’re building a large enterprise application or a one that is publicly available you may want to introduce a concept of users, so that they will be able login to their accounts, put their information and do some stuff with your app, if they’re allowed to. With this blog post I would like to show how it could be implemented in Angular application using OAuth 2.0 and OpenID Connect frameworks an integrate it with a popular, open source identity provider — Keycloak.

The goal

For a purpose of this article I’ve prepared a very simple application which could be used to find out information about movies and display them in a table. Application supports two actions — either fetch all the data or select a single movie by its id.

> docker-compose up -d backend
>  docker ps
IMAGE STATUS NAMES
keycloak-security-example_backend Up About a minute backend
jboss/keycloak:11.0.2 Up About a minute keycloak
postgres:13.0-alpine Up About a minute postgres
127.0.0.1	keycloak

Register frontend application in Keycloak

username: admin
password: admin

Main view of a page

Now we can deep dive into Angular project. It has only one component (apart from AppComponent) - ContentComponent.

server {    listen 80;
server_name frontend;
root /usr/share/nginx/html;
index index.html index.html;
location /movies {
proxy_pass http://backend:9000/movies;
} location / {
try_files $uri $uri/ /index.html;
}
}

Basic configuration of Keycloak libraries

First step would be to add keycloak-angular dependencies to the project, therefore in a terminal run following command:

> npm install keycloak-angular keycloak-js
> ng g class init/keycloak-init --type=factory --skip-tests
CREATE src/app/init/keycloak-init.factory.ts (22 bytes)
> ng g guard guard/auth --skip-tests? Which interfaces would you like to implement? CanActivate
CREATE src/app/guard/auth.guard.ts (458 bytes)
> npm start> frontend@0.0.0 start .\keycloak-security-example\frontend
> ng serve --proxy-config src/assets/proxy.conf.dev.json
- Generating browser application bundles...[HPM] Proxy created: /movies -> http://localhost:9000
[HPM] Subscribed to http-proxy events: [ 'error', 'close' ]
√ Browser application bundle generation complete.
Initial Chunk Files | Names | Size
vendor.js | vendor | 5.11 MB
styles.css, styles.js | styles | 562.38 kB
polyfills.js | polyfills | 493.08 kB
main.js | main | 40.76 kB
runtime.js | runtime | 6.15 kB
| Initial Total | 6.18 MBBuild at: 2021-02-20T15:55:55.362Z - Hash: 360dd85cc05c08ec0698 - Time: 14478ms** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
√ Compiled successfully.
username: han/luke
password: password

Productionize Keycloak configuration

So far so good, we’ve got a working piece of code. But there is one problem with this approach. If we would need to change the Keycloak’s URL, realm name or client (development, test and production environment can be different) we would be forced to change it in the code for each version, as all these values are hardcoded.

> ng g service init/config-init --skip-tests
CREATE src/app/init/config-init.service.ts (140 bytes)
server {
listen 80;
server_name frontend;
root /usr/share/nginx/html;
index index.html index.html;
location /movies {
proxy_pass ${BACKEND_BASE_PATH}/movies;
}
location / {
try_files $uri $uri/ /index.html;
}
}
version: "3.8"

services:

frontend:
build: ./frontend
container_name: frontend
ports:
- 80:80
environment:
- KEYCLOAK_URL=http://keycloak:8080
- KEYCLOAK_REALM=test
- KEYCLOAK_CLIENT_ID=frontend
- BACKEND_BASE_PATH=http://backend:9000
depends_on:
- keycloak
- backend

# definitions of other services
> docker-compose up -d frontend
> docker ps

CONTAINER ID STATUS NAMES
1840d7564aeb Up 46 seconds frontend
cba18013881c Up 47 seconds backend
01f15608d210 Up 47 seconds keycloak
ac67959019f9 Up 48 seconds postgres

References

Java Software Developer, DevOps newbie, constant learner, podcast enthusiast.