The APIs are protected by Keycloak IAM. Two libraries were used:
- keycloak-connect: to manage the protection of routes
- keycloak-admin-client: to query Keycloak via API
See the official documentation
-
Create new realm (
KEYCLOAK_REALM
) -
Go to "Clients" section and create new client (
KEYCLOAK_CLIENT_ID
)- Set
Access Type
asconfidential
- Enable
Standard Flow Enabled
,Implicit Flow Enabled
andDirect Access Grants Enabled
- Go to "Credentials" tab to get the secret (
KEYCLOAK_CLIENT_SECRET
) - Go to "Roles" tab to make new application roles:
admin
,user
- Set
-
Go to "Roles" section and create new
nodejs-kc-admin
role- Enable
Composite Roles
and from "Client Roles"realm-management
add the following roles:manage-clients
manage-users
view-clients
view-users
- Enable
-
Go to "Users" section and create new
api-kc-admin
(KEYCLOAK_API_ADMIN_USERNAME
) user with a non-temporary password (KEYCLOAK_API_ADMIN_PASSWORD
)- From "Role Mappings" tab add
nodejs-kc-admin
"Realm Roles" - Make sure you don't reuse
nodejs-kc-admin
role to other users (Only used for api calls from the nodejs backend)
- From "Role Mappings" tab add
-
Put the information inside the application
.env
file -
Go to "Roles" section and create new
app-admin
,app-user
roles- For each role enable
Composite Roles
and from Client ID just created in "Client Roles" associate:
admin
inapp-admin
user
inapp-user
Use
app-admin
,app-user
roles to identify and associate app user roles - For each role enable
Notes:
- Make sure the Client ID
admin-cli
is enabled - For test make sure the "Require SSL" is
none
in Realm Settings -> Login (tab); Enable "Require SSL" after https configuration.
For better use, the two libraries have been grouped into a custom class: KeycloakHelper, located in src\helpers\keycloak-helper.ts
and is initialized in src\app.ts
.
You can protect a route by KeycloakHelper.protect(role?: string)
method.
Each client to make a request must insert the Authorization
in the header as Bearer {{accessToken}}
.
- If the
accessToken
has expired or is not valid a response of typeIStatusMessage
with401
code will be returned - If a role has been specified in the
protect
method and the user has not associated that role a response of typeIStatusMessage
with403
code will be returned
The accessToken it must be retrieved by logging into keycloak
import KeycloakHelper from "../helpers/keycloak-helper";
...
const router = express.Router();
// All roles
router.use('/your-route', KeycloakHelper.protect(), anyController);
// Specific role
router.use('/your-route', KeycloakHelper.protect(environment.appRoles.admin), anyController);
To make a Keycloak query you need the KeycloakHelper.adminClient
and then you call the supported APIs.
const kcAdminClient = KeycloakHelper.adminClient;
const kcUsers = await kcAdminClient.users.find(); // Keycloak query
// Retrieve the current user from the request (who made the request)
const currentUser = KeycloakHelper.getCurrentUser(req)!;
// Perform live validation of an access_token against the Keycloak server.
// return false if the token is invalid, the same token if valid or if is specified a UserRepresentation.
const accessToken = await KeycloakHelper.validateAccessToken(data, false);
// Retrieves the current Client
const client = await KeycloakHelper.getClient();