How to Setup Role Based Access Control (RBAC) with Keycloak
- Share:
Role-Based Access Control (RBAC) is an essential framework for assigning permissions and ensuring users can only access resources aligned with their roles.
Keycloak, an open-source Identity and Access Management (IAM) tool, simplifies user authentication and provides great support for implementing access control systems.
Keycloak also has open protocol support and is based on standard protocols such as OpenID Connect and SAML 2.0. So it's a perfect choice for features like Identity Federation or Single Sign-On (SSO).
However, while Keycloak includes basic role-based permissions, it lacks the ability to dynamically manage and scale RBAC configurations across complex applications.
In this guide, we will demonstrate how to integrate dynamic RBAC into an application using Keycloak and Permit.io. Permit enhances Keycloakâs capabilities by introducing fine-grained permissions, dynamic policies, and support for additional access control models like Attribute-Based Access Control (ABAC) and Relationship-Based Access Control (ReBAC).
By the end of this article, youâll have a clear understanding of:
- Setting up Keycloak for authentication and initial RBAC configuration.
- Leveraging Permit to implement dynamic permissions in a NestJS application.
- Synchronizing users and roles between Keycloak and Permit to ensure seamless access control.
Whether youâre looking to manage multi-tenant applications, secure API endpoints, or scale your RBAC policies dynamically, this tutorial will provide actionable steps and code examples to help you get started.
Keycloak RBAC: Built-In Features and Their Limitations
Keycloak provides built-in support for Role-Based Access Control (RBAC), making it straightforward to define and manage user roles within its admin console. Roles in Keycloak are divided into two main categories:
- Realm Roles: Global roles that can be applied across all applications (clients) within a Keycloak realm.
- Client Roles: Roles that are specific to individual clients (applications) and provide more granular control.
With these features, developers can create hierarchical roles, assign permissions, and secure endpoints.
When Keycloak Built-In RBAC Falls Short
While Keycloak RBAC capabilities are useful for many scenarios, they may lack flexibility in more complex environments:
- Limited Fine-Grained Permissions: Keycloak's roles are static and coarse-grained, making it challenging to manage detailed, context-specific permissions (e.g., granting access to specific resources for specific actions).
- Dynamic Policies: There is no built-in mechanism to handle dynamic conditions, such as granting access based on user attributes, relationships, or real-time contextual factors.
- Complex Multi-Tenancy: Managing permissions across multiple tenants (like organizations) requires custom workarounds.
- Policy Management at Scale: Updating and maintaining roles and permissions across a growing application can become tedious, especially in systems with frequent changes.
Enhancing Keycloak RBAC with Dynamic Access Control
To address these limitations, Permit.io offers an advanced permissions management platform seamlessly integrating with Keycloak. By combining Keycloak's authentication features with Permitâs fine-grained access control, you gain:
- Dynamic RBAC: Define and enforce detailed permissions that adapt to changing user roles, actions, and application states.
- ABAC and ReBAC Support: For even greater flexibility, extend beyond roles with Attribute-Based Access Control (ABAC) and Relationship-Based Access Control (ReBAC).
- Multi-Tenancy Simplified: Manage tenants, user groups, and permissions efficiently across organizations without custom code.
- Policy-as-Code and No-Code Tools: Gives developers and non-technical team members the tools to create, test, and manage policies.
By integrating Permit with Keycloak, you can implement dynamic, scalable, and secure access control without overloading your application logic. Without further adieu, letâs get started!
Setup Nest JS Project
First, we have to set up our nest.js project. Here, we will use the NestJS CLI, simplifying project setup and development tasks.
Install the CLI globally:
npm install -g @nestjs/cli
Check if the CLI is installed correctly:
nest --version
Generate a new NestJS project using the CLI:
nest new project-name
Replace project-name
with the desired name of your project.
Cool! Your project should be installed. You can run it by using npm start:dev
Keycloak Configuration
Before diving into dynamic RBAC with Permit, itâs essential to take care of basic Keycloak configurations. This section will guide you through setting up Keycloak to prepare for integration with your application.
1. Set up the Keycloak server
We can set up a Keycloak instance in multiple ways, depending on our environment and preferences. Follow the instructions in the official documentation for your specific installation method.
After completing the setup, log in to the Keycloak admin console using the administrative credentials you created during the installation process.
Once you have logged in with admin credentials, you will be directed to the Keycloak dashboard, with the master realm selected by default.
2. Create a Realm
A realm in Keycloak is responsible for securing and managing security metadata for a group of users, applications, and registered OAuth clients.
You can create a new realm by selecting the dropdown from the top left, when the master realm is selected.
By clicking "Create Realm," you will be redirected to the realm creation page where you need to specify the realm name, as shown below:
Once you create the realm, you will be directed to the newly created realm's page.
NOTE: Always ensure that the desired realm is selected before making any changes or configurations, as all settings and configurations are specific to the selected realm.
In our setup, the realm we created, keycloak-with-permit
is already selected. Now, we will navigate to the "Realm Settings" to proceed with the configuration.
In the Realm Settings, you'll find a variety of options to configure Keycloak according to your requirements. Currently, I am on the Login tab, and I want to draw your attention to the "Email Settings" section. Here, you can easily customize settings to suit your needs. For example, as shown, I have enabled "Email as username" and "Login with email" by setting them to true.
Another essential feature to configure is the Access Token Lifespan. This setting allows you to adjust the duration for which an access token remains valid. You can increase or decrease the token's lifespan as needed. This option is available under the "Token" tab on the Realm Settings page.
3. Create Clients
Clients in Keycloak are applications or services that depend on Keycloak for user authentication. These clients typically leverage Keycloak to implement Single Sign-On (SSO) and secure their interactions. In addition to securing applications, clients can request identity details or access tokens from Keycloak, enabling secure communication with other services protected by Keycloak.
Note: Ensure that you select the appropriate realm. In this case, the realm would be: âkeycloak-with-connectâ.
From the left sidebar, navigate to the Clients page, where you can manage your application clients. To create a new client, click the Create Client button.
You will see three tabs that need to be reviewed. On the first tab, the Client ID is required, but adding a Name is also recommended. Letâs proceed by adding the Client ID and Name.
I have added the Client ID as keycloak-with-permit
, which must be unique. I have also provided a Client Name, as shown on the screen. Once done, click Next.
The Capability Config tab is important, as it enables the Authentication and Authorization flow. Ensure you configure the settings as shown in the image above. Once done, proceed to the next step, where we will configure the Login Settings.
On the Login Settings page, you typically donât need to make any changes, as the default settings allow the origin. However, if you use the Keycloak login page, you must specify the redirect URL where Keycloak will redirect users after login along with the token. This is an important step. You can add multiple URLs by clicking the plus icon below the input field.
Once configured, click the Save button. Your client will be created, and you will see it listed on the Clients page.
Amazing! We have successfully created a Nest.js app, set up our Keycloak configuration, created a realm in Keycloak, and added a client.
Setup Keycloak with Nest.js
Now, we will connect Keycloak with our Nest.js app. To do this, we need an npm package called nest-keycloak-connect
. We will install this package in our Nest.js project.
npm install nest-keycloak-connect
Now, we need to add the Keycloak configuration to NestJS. Here, we are adding the configuration to the app.module.ts
. However, if preferred, you can create a separate module for the Keycloak configuration and import that module into app.module.ts
.
Here, you can see the KeycloakConnectModule
that we are using to integrate Keycloak with our Nest.js project. However, we need some important information from Keycloak to establish the connection with Nest.js.
KeycloakConnectModule.register({
authServerUrl: process.env.KEYCLOAK_AUTH_URL,
realm: process.env.KEYCLOAK_REALM,
clientId: process.env.KEYCLOAK_ADMIN_CLIENT_ID,
secret: process.env.KEYCLOAK_ADMIN_CLIENT_SECRET,
}),
We need the authServerUrl
, which can be found on the realm settings page in Keycloak.
Click on the âOpenID Endpoint Configurationâ link, and you will be redirected to a JSON file containing the list of endpoints.
Here, we can see the authServerUrl
, which in our case is http://0.0.0.0:8080
. Simply copy and paste it into our .env file.
As for the realm, itâs easy to findâjust get it from the dropdown in the top left corner.
In our case, keycloak-with-permit
is our realm, and you can add it to your .env file.
The same applies to the client ID. You can find it on the Clients page, which I showed earlierâI believe youâll be able to locate it. Now, I want to show you where to find the client secret.
To get the client secret, go to the Clients tab in the left sidebar, then navigate to the Credentials tab. There, you will find the credentialsâjust copy them and save them in your .env file.
Great! We have everything we need to connect to NestJS. Here is the full code for the app.module.ts
file, which you can view below:
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { KeycloakConnectModule } from 'nest-keycloak-connect';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: ['.env'],
}),
KeycloakConnectModule.register({
authServerUrl: process.env.KEYCLOAK_AUTH_URL,
realm: process.env.KEYCLOAK_REALM,
clientId: process.env.KEYCLOAK_ADMIN_CLIENT_ID,
secret: process.env.KEYCLOAK_ADMIN_CLIENT_SECRET,
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Your app.module.ts
file will look like this after adding the Keycloak configuration.
The Keycloak setup is almost complete. We have configured Keycloak and integrated it with Nest.js. Now, as mentioned, we will use Permit.io for authorization. Letâs configure it and install it in our Nest.js app.
Setup Permit
To begin setting up permissions, go to app.permit.io and log in. Once youâre signed in, the next step is to create a new workspace for your project.
The next step is to create a resource. After launching your account, you will land on the Permit dashboard.
Go to the Policy page, where you will be able to create a Resource. A resource can be any endpoint, object, class, etc.
Here, âprofileâ will be one of the endpoints. We have added âviewâ as an action. Actions refer to the ways a user can interact with a resource. You will also see two options: ABAC and ReBACâwe will discuss these in more detail later.
Once you save it and navigate to the Policy Editor page, you will see three default roles, each with a corresponding grid, as shown in the image above.
I have now added Admin, User, and Manager roles, as shown in the Roles tab in the image above.
Cool! So far, weâve covered how to create a workspace, how to create resources, and how to create roles. Now, letâs integrate Permit with the Nest project, and then weâll dive deeper into the authentication and authorization process.
Setup Permit with Nest.js
To set up Permit with Nest.js, we will use a package called permitio
. Letâs install it in our Nest.js project.
npm install permitio
Once itâs installed, we need to configure it in our app.module.ts
file.
Here, you can see the PDP URL, which will be: https://cloudpdp.api.permit.io
. We also need the token, which you can simply copy from the Permit.
Here, you will be able to copy your environment key and set it in the .env
file. As shown in the Permit setup, we are retrieving the token from the .env
file.
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { KeycloakConnectModule } from 'nest-keycloak-connect';
import { Permit } from 'permitio';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PermissionsGuard } from './auth/permission.guard';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: ['.env'],
}),
KeycloakConnectModule.register({
authServerUrl: process.env.KEYCLOAK_AUTH_URL,
realm: process.env.KEYCLOAK_REALM,
clientId: process.env.KEYCLOAK_ADMIN_CLIENT_ID,
secret: process.env.KEYCLOAK_ADMIN_CLIENT_SECRET,
}),
],
controllers: [AppController],
providers: [
AppService,
{
provide: 'PERMITIO_CLIENT',
useFactory: () => {
return new Permit({
pdp: '<https://cloudpdp.api.permit.io>',
token: process.env.PERMIT_TOKEN,
});
},
},
PermissionsGuard,
],
})
export class AppModule {}
Here is what the full app.module.ts
file will look like after setting up both Keycloak and Permit.
Authorization using Permit
Now, letâs try to understand how our endpoint works and how we have defined our permissions to determine who can access what. Believe it or not, this is as straightforward as the way weâve been discussing it.
@Get('users')
@UseGuards(PermissionsGuard)
@Permissions('view:users', 'list:users')
getAllUsers() {
// This route requires both 'view:users' and 'list:users' permissions
return [
{ id: 1, name: 'test' },
{ id: 2, name: 'test 2' },
];
}
This is one of our endpoints. Here, we are explicitly stating in the @Permission
decorator that the usersâ list will be accessible to anyone with the view
action permission.
In the policy above, you can see that the Manager role has both list
and view
action permissions, whereas the Admin role does not have either. If I assign the Admin role to someone, they will not be able to access the /users
endpoint. On the other hand, someone with the Manager role will have access. Weâll see this in action very soon.
But letâs take a moment to understand how this permission guard works.
Iâll demonstrate the full implementation of the permission guard, but first, I want to show you an amazingly simple permission-checking function from Permit.
await this.permit.check(user.email, action, resource);
This check function takes three parameters: the email, the action the user wants to perform, and the resource the user wants to access. Based on this information, Permit will return either true or false. If the user has permission, it will return true; otherwise, it will return false. Isnât that amazing?
// permission.guard.ts
import {
CanActivate,
ExecutionContext,
Inject,
Injectable,
SetMetadata,
UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Permit } from 'permitio';
// Decorator to define permissions dynamically
export const Permissions = (...permissions: string[]) =>
SetMetadata('permissions', permissions);
@Injectable()
export class PermissionsGuard implements CanActivate {
constructor(
private reflector: Reflector,
@Inject('PERMITIO_CLIENT') private readonly permit: Permit,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const requiredPermissions = this.reflector.get<string[]>(
'permissions',
context.getHandler(),
);
// If no specific permissions are defined, allow access
if (!requiredPermissions || requiredPermissions.length === 0) {
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user || null;
if (!user || !user.email) {
throw new UnauthorizedException('User not authenticated');
}
try {
const permissionChecks = requiredPermissions.map(async (permission) => {
const [action, resource] = permission.split(':')
return await this.permit.check(user.email, action, resource);
});
// Ensure all required permissions are granted
const permissionResults = await Promise.all(permissionChecks);
const hasAllPermissions = permissionResults.every((result) => result);
if (!hasAllPermissions) {
throw new UnauthorizedException(
'You do not have the necessary permissions.',
);
}
return true;
} catch (error) {
console.error('Permission check failed:', error);
throw new UnauthorizedException('Permission verification failed');
}
}
}
This provides a way to secure endpoints in a NestJS application by checking if a user has specific permissions using the Permit.io
service.
Dynamic Permissions with Decorator:
The
Permissions
decorator (SetMetadata
) allows you to define the required permissions for a specific route dynamically.@Permissions('read:resource', 'write:resource') someHandler() {}
Guard for Permission Enforcement:
The
PermissionsGuard
checks if the current user has all the required permissions:- It retrieves the permissions from the handler using
Reflector
. - If no permissions are defined, access is granted.
- Otherwise, it validates if the user is authenticated (checks
request.user
). - It dynamically verifies the user's permissions using
Permit.check
.
Permission Verification Logic:
- Required permissions (e.g.,
read:resource
) are split intoaction
(read
) andresource
(resource
). - These are checked for the user via
Permit.io
.
If all permissions pass, the request proceeds; otherwise, access is denied with an
UnauthorizedException
.
Now, itâs pretty clear how our permission checks are happening through the decorator and with the help of Permit.io. If you look at the implementation, weâre retrieving the user data from the request. Essentially, when a request comes in, we check if the authorization header is present. If it is, we decode the JWT, find the user, and attach the user data to the request object. If no authorization header is found, we set it to null, as there might be some public endpoints.
In this tutorial, we will use the Keycloak REST API to create and log in users. The goal is to ensure that when we create a user in Keycloak, we also create the same user in Permit, allowing us to sync users between Keycloak and Permit seamlessly.
Once we have the user data, we can assign a default role to the Permit user, such as the âUserâ role.
Letâs see how we can implement this in our code:
// app.service.ts
import { Inject, Injectable } from '@nestjs/common';
import axios from 'axios';
import { Permit } from 'permitio';
interface UserCreationDto {
username: string;
firstName: string;
lastName: string;
email: string;
password: string;
}
@Injectable()
export class AppService {
constructor(@Inject('PERMITIO_CLIENT') private readonly permit: Permit) {}
async createUser(userDto: UserCreationDto) {
try {
// 1. Create User in Keycloak
const keycloakResponse = await this.createKeycloakUser(userDto);
// 2. Create User in Permit.io
const permitUser = await this.createPermitUser(userDto);
// 3. Assign Default Role in Permit.io
await this.assignDefaultRole(permitUser.key);
return {
keycloak: keycloakResponse,
permit: permitUser,
};
} catch (error) {
console.error('User creation failed:', error);
throw new Error('Failed to create user');
}
}
async createKeycloakUser(userDto: UserCreationDto) {
try {
const response = await axios.post(
`${process.env.KEYCLOAK_AUTH_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users`,
{
username: userDto.username,
firstName: userDto.firstName,
lastName: userDto.lastName,
email: userDto.email,
emailVerified: false,
enabled: true,
credentials: [
{
type: 'password',
value: userDto.password,
},
],
},
{
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${await this.getAdminToken()}`,
},
},
);
return response.data;
} catch (error) {
console.error(
'Keycloak user creation failed:',
error.response?.data || error.message,
);
throw error;
}
}
private async createPermitUser(userDto: UserCreationDto) {
return this.permit.api.users.create({
key: userDto.username,
email: userDto.email,
first_name: userDto.firstName,
last_name: userDto.lastName,
});
}
private async assignDefaultRole(userKey: string) {
// Assign a default role to the user in Permit.io
await this.permit.api.assignRole({
role: 'User',
tenant: 'default',
user: userKey,
});
}
private async getAdminToken() {
try {
const response = await axios.post(
`${process.env.KEYCLOAK_AUTH_URL}/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/token`,
new URLSearchParams({
grant_type: 'client_credentials',
client_id: process.env.KEYCLOAK_ADMIN_CLIENT_ID,
client_secret: process.env.KEYCLOAK_ADMIN_CLIENT_SECRET,
}),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
},
);
return response.data.access_token;
} catch (error) {
console.error('Failed to get admin token:', error);
throw error;
}
}
}
We are creating users in both Keycloak and Permit and assigning a default role to all Permit users. We need an admin token when creating a Keycloak user, which is why we created a getAdminToken
function to retrieve the token and attach it to the headers.
We have a couple of endpoints in our app.controller.ts
file. Letâs take a look at which permissions are associated with each endpoint.
import {
Body,
Controller,
Get,
Post,
UnauthorizedException,
UseGuards,
} from '@nestjs/common';
import axios from 'axios';
import * as qs from 'qs';
import { AppService } from './app.service';
import { Permissions, PermissionsGuard } from './auth/permission.guard';
interface UserCreationDto {
username: string;
firstName: string;
lastName: string;
email: string;
password: string;
}
interface LoginDto {
username: string;
password: string;
}
interface TokenResponse {
access_token: string;
expires_in: number;
refresh_token: string;
refresh_expires_in: number;
token_type: string;
}
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get('users')
@UseGuards(PermissionsGuard)
@Permissions('view:users', 'list:users')
getAllUsers() {
// This route requires both 'view:users' and 'list:users' permissions
return [
{ id: 1, name: 'test' },
{ id: 2, name: 'test 2' },
];
}
@Get('/profile')
@UseGuards(PermissionsGuard)
@Permissions('view:profile')
getUserProfile() {
// This route requires 'view:profile' permission
return {
data: 'You are accessing profile information',
};
}
@Get('/admin')
@UseGuards(PermissionsGuard)
@Permissions('view:dashboard')
getAdminDashboard() {
// This route requires 'view:dashboard' permissions
return {
data: 'You are accessing dashboard content',
};
}
@Post('/create-user')
async createUser(@Body() createUserDto: UserCreationDto) {
return this.appService.createUser(createUserDto);
}
@Post('login')
async login(@Body() loginDto: LoginDto) {
try {
const tokenUrl = `${process.env.KEYCLOAK_AUTH_URL}/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/token`;
const requestData = qs.stringify({
grant_type: 'password',
client_id: process.env.KEYCLOAK_ADMIN_CLIENT_ID,
client_secret: process.env.KEYCLOAK_ADMIN_CLIENT_SECRET,
username: loginDto.username,
password: loginDto.password,
});
const response = await axios.post<TokenResponse>(tokenUrl, requestData, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
});
// Optional: Decode and extract user info from access token
const decodedToken = this.decodeToken(response.data.access_token);
return {
access_token: response.data.access_token,
refresh_token: response.data.refresh_token,
user: {
username: decodedToken.preferred_username,
email: decodedToken.email,
name: decodedToken.name,
},
expires_in: response.data.expires_in,
};
} catch (error) {
// Handle login failure
if (error.response) {
throw new UnauthorizedException('Invalid credentials');
}
throw new UnauthorizedException('Login failed');
}
}
// Helper method to decode JWT token
private decodeToken(token: string): any {
try {
const base64Url = token.split('.')[1];
const base64 = base64Url.replace('-', '+').replace('_', '/');
return JSON.parse(Buffer.from(base64, 'base64').toString('utf-8'));
} catch (err) {
throw new UnauthorizedException('Invalid token', err);
}
}
}
Routes like /users
, /profile
, and /admin
are protected with a PermissionsGuard
, as indicated by the specified permissions. Additionally, we have the /create-user
and /login
endpoints for creating users and logging them in through Keycloak.
This is my Keycloak user list, and itâs currently empty since we donât have any users.
This is my Permit user list, and since we donât have any users, itâs obviously empty.
Now, we will use Postman to create a user and check both Keycloak and Permit to see if the user is synced.
Here, I have created a user using our /create-user
endpoint, and we received a response. The email is: syketb@gmail.com.
Letâs check both Keycloak and Permit to see if the user appears in both places.
The newly created user is in Keycloak, and the red dot indicates that the email is not verified, which is not an issue.
In Permit, we can see a new user created with our default role, which is âUser.â Now, the user is created in both Keycloak and Permit. Letâs try logging in using our endpoint.
As you can see, we received a response with an access_token
and refresh_token
. We will decode the token using jwt.io to examine the data it contains. Since this token is generated by Keycloak, we can say it has been authenticated by Keycloak.
As you can see, the access_token
contains this information, which means it is working properly.
Now, the question is: Will this user be able to get the user list? Letâs find out. Since we have a permission restriction on the /users list endpoint, we need to send the authorization header when making the request.
No, we wonât be able to get the user list because, in the Permit policy, we didnât specify that the âUserâ role has âviewâ and âlistâ action permissions. Letâs assign these action permissions to the âUserâ role and see what happens.
Now that our âUserâ role has both âlistâ and âviewâ action permissions, the user should be able to see the user list, as we specified in our app.controller.ts
file that anyone who wants to access the user list must have the view
and list
permissions. Letâs check in Postman now.
Now I can access the user list. How simple is that? Isnât it amazing? Additionally, we can update the user role in Permit, as you can see here.
Multi-Tenancy RBAC with Keycloak
Multi-tenancy and group management are essential features for applications serving multiple organizations or hierarchical user structures. Both Keycloak and Permit provide tools to implement these features, but Permit introduces greater flexibility and scalability for managing complex use cases.
In Keycloak, an organization within a realm can be seen as the equivalent of a tenant in Permit. Permit supports creating multiple tenants, making it a natural complement to Keycloakâs multi-tenancy model. Learn more about Permitâs multi-tenancy capabilities here.
Both Keycloak and Permit allow managing shared characteristics and role mappings through groups. In Keycloak, groups bundle users together to simplify permission assignments. Similarly, Permit provides dynamic group management, making it easy to assign permissions collectively instead of managing individual users. Permitâs Group APIs offer further flexibility and can be explored here.
Next Steps
Integrating RBAC into your application using Keycloak and Permit.io offers a powerful combination of authentication and dynamic access control. Keycloak provides a strong foundation for managing user authentication, while Permit enhances this with advanced authorization capabilities, including dynamic RBAC, ABAC, and ReBAC. Together, they enable scalable, secure, and flexible access management for applications of any complexity.
By following this guide, youâve learned how to:
- Configure Keycloak for authentication and role-based access control.
- Integrate Permit.io to implement dynamic permissions and fine-grained access control.
- Sync users and roles across Keycloak and Permit to streamline multi-tenancy and group management.
Ready to take your access control to the next level?
Explore more with Permit:
- Get Started with Permit.io and simplify your access control setup today.
- Dive deeper into Permitâs documentation to explore advanced features like policies and multi-tenancy.
- Check out related articles on integrating Keycloak with other tools and frameworks to further enhance your applicationâs capabilities.
Want to learn more? Got questions? Join our Slack community, where there are hundreds of devs building and implementing authorization.
Written by
Daniel Bass
Application authorization enthusiast with years of experience as a customer engineer, technical writing, and open-source community advocacy. Comunity Manager, Dev. Convention Extrovert and Meme Enthusiast.