npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@libstack/keycloak

v1.1.0

Published

Libstack Server - Keycloak Integration

Downloads

3

Readme

@libstack/keycloak

Adds keycloak integration to your @libstack/server.

Installing

npm install @libstack/keycloak --save

New env variables

  • KEYCLOAK_ENABLED: Must be true to enable the integration
  • KEYCLOAK_AUTH_URL: This is the auth url for keycloak authorization
  • KEYCLOAK_CLIENT_ID: The client ID to use
  • KEYCLOAK_CLIENT_SECRET: The client Secret to use
  • KEYCLOAK_REALM: The keycloak realm

Integrate to your routes

In order to enable integration, your routes need to have a custom property { roles: ['admin'] } Where roles will be the client resource roles.

So, we recommend on creating realm-roles on your keycloak and having them as composite with the client roles. You will assign the realm-roles to your users.

Sample code

import { GET, RestController } from '@libstack/server';

@RestController('/v1/test')
class TestRouter {

  @GET('/unauthorized')
  async unauthorizedRoute():Promise<any> {
    return { authorized: false };
  }

  @GET('/authorized', { roles: ['admin'] })
  async authorizedRoute():Promise<any> {
    return { authorized: true };
  }
}

And then you will need to enable the keycloak interceptor on your application by just importing the keycloak module.

Plug in the keycloak interceptor on your application

import '@libstack/keycloak';

Creating users and groups

Keycloak service has users and groups which you can manage as you want.

Important note:

To be able to perform those actions your client will need to have service account roles enabled and will need to have permission realm-admin on realm-management , otherwise you will see some 403 errors.

User Service

@libstack/keycloak has a class to manage users for your application. All you will need to do is import keycloakUserService.

import { keycloakUserService } from '@libstack/keycloak';

User service methods

Here are the methods available on user service

Create User

There is one method to create users. It will return the userId from keycloak, store it on the record you want to link with the user.

async createUser(user: UserRepresentation): Promise<string>

This method throws UserCreationError when the username or email is already being used.

Update User

There is one method to update an user. You need to provide the userId to perform the update and the data you want to change.

async updateUser(userId: string, user: UserRepresentation): Promise<void>

This method also throws UserCreationError when the new username or email is already being used.

Get User

There is one method to return user data. You need to provide the userId from the user.

async getUser(userId: string): Promise<UserRepresentation>
Delete User

There is one method to delete the user from keycloak (along with his/her access to the application).

async deleteUser(userId: string): Promise<void>
Reset user password

You can also reset the user's password by calling the method described below.

async resetUserPassword(userId: string, password: string, temporary: boolean = false)

If you set the temporary flag to true, once the user logs in into the application, he will be asked to change the password imediatelly.

Send email to user with required actions

There is one method to send emails with required actions, and they are:

  • Update password
  • Configure OTP (One time password)
  • Verify email
  • Update user profile (first name, last name and email)
async executeActionsEmail(userId: string, payload: ActionsEmail)

You will need to also provide the redirectUri and clientId so the user will be automatically redirected to your frontend application once he finishes the configuration.

Group Service

In keycloak, groups are more related to the user's permissions. So, instead of assigning roles directly to the users, it's recommended to create a group, assign the roles to it and then add users to the group, this way will give more controls on all users on a given profile.

@libstack/keycloak has a class to manage groups for your application. All you will need to do is import keycloakGroupService.

import { keycloakGroupService } from '@libstack/keycloak';

Group service methods

Here are the methods available on user service

Create Group

There is one method to create groups. It will return the groupId from keycloak, store it on the record you want to link with the group.

async createGroup(group: GroupRepresentation): Promise<string>

This method throws GroupCreationError when the group name is already being used.

Update Group

There is one method to update a group. You need to provide the groupId to perform the update and the data you want to change.

async updateGroup(groupId: string, group: GroupRepresentation): Promise<void>

This method also throws GroupCreationError when the group name is already being used.

Get Group

There is one method to return group data. You need to provide the groupId from the group.

async getGroup(groupId: string): Promise<GroupRepresentation>
Delete Group

There is one method to delete the group from keycloak, but it won't delete any users inside of it. If you want to do so, you will need to delete all users manually.

async deleteUser(userId: string): Promise<void>
Listing Group members

You can list all group members by just providing the groupId.

async listGroupMembers(groupId: string, first: number = 0, max: number = 100): Promise<UserRepresentation []>
Adding users to the group

To add new users to the group, you just need to pass the groupId and the userId.

async addMember(groupId: string, userId: string): Promise<void>
Removing users from the group

To remove users from the group, you just need to pass the groupId and the userId present on the group.

async removeMember(groupId: string, userId: string): Promise<void>
Adding/Removing realm roles to the group

So you can create groups and add users to them, but you will need to assign roles to the groups so users will indirectly have those roles. In order to do so, you need to get the realm role by using the keycloakClient and then you can assign the roles to the group.

async addRealmRole(groupId: string, role: RoleRepresentation|RoleRepresentation []): Promise<void>;

async removeRealmRole(groupId: string, role: RoleRepresentation|RoleRepresentation []): Promise<void>;

The code below will show how to do this:

import { 
  keycloakClient, 
  keycloakGroupService, 
  RoleRepresentation
} from '@libstack/keycloak';

async function addRoleToGroup(groupId: string, roleName: string) {
  const role: RoleRepresentation = await keycloakClient.getRealmRole(roleName);
  await keycloakGroupService.addRealmRole(groupId, role);
}

async function removeRoleFromGroup(groupId: string, roleName: string) {
  const role: RoleRepresentation = await keycloakClient.getRealmRole(roleName);
  await keycloakGroupService.removeRealmRole(groupId, role);
}

Using session user from Keycloak

In order to use the session user from Keycloak you will need to make sure the route is authenticated and you must use the KeycloakRequest on the Express route.

import { GET, RestController } from '@libstack/server';
import { KeycloakRequest } from '@libstack/keycloak';

@RestController('/v1/test')
class TestRouter {

  @GET('/authorized', { roles: ['admin'] })
  async authorizedRoute(request: KeycloakRequest):Promise<any> {
    return { username: request.session?.username };
  }
}

If you want to get more details from the user, like the user's attributes, you will need to use keycloakUserService.