<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: OUMERZOUG Haïtham</title>
    <description>The latest articles on DEV Community by OUMERZOUG Haïtham (@haithamoumer).</description>
    <link>https://dev.to/haithamoumer</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2677802%2F0a00bc64-6434-4862-b7d5-5bcbe1902ae8.jpeg</url>
      <title>DEV Community: OUMERZOUG Haïtham</title>
      <link>https://dev.to/haithamoumer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/haithamoumer"/>
    <language>en</language>
    <item>
      <title>Coders, Software Engineers &amp; AI: Building the Future Together</title>
      <dc:creator>OUMERZOUG Haïtham</dc:creator>
      <pubDate>Wed, 18 Jun 2025 17:01:23 +0000</pubDate>
      <link>https://dev.to/haithamoumer/coders-engineers-ai-building-the-future-together-54kb</link>
      <guid>https://dev.to/haithamoumer/coders-engineers-ai-building-the-future-together-54kb</guid>
      <description>&lt;h2&gt;
  
  
  Introduction:
&lt;/h2&gt;

&lt;p&gt;In today's fast-moving tech world, the line between &lt;strong&gt;coders&lt;/strong&gt; and &lt;strong&gt;software engineers&lt;/strong&gt; is becoming increasingly blurred, and &lt;strong&gt;AI&lt;/strong&gt; is at the heart of this shift.&lt;/p&gt;

&lt;p&gt;Whether you're building simple scripts or architecting entire platforms, AI tools like &lt;strong&gt;GitHub Copilot&lt;/strong&gt;, &lt;strong&gt;ChatGPT&lt;/strong&gt;, &lt;strong&gt;Claude&lt;/strong&gt; and other intelligent assistants are transforming how we write code, design systems, and solve problems. These tools are not just helping with automation; they're reshaping the very nature of software development.&lt;/p&gt;

&lt;p&gt;As companies race to innovate faster and more efficiently, it's crucial to understand the difference between coders and software engineers, and how AI is bridging the gap, elevating both roles into something more powerful and collaborative than ever before.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Who is a Coder?
&lt;/h2&gt;

&lt;p&gt;A coder is someone who writes code, and often focusing on solving specific tasks or implementing distinct functionalities. Their primary strength is in syntax, logic, and understanding programming languages.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; A coder may be asked to build a login form, landing page or automate a repetitive task using Python.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Who is a Software Engineer?
&lt;/h2&gt;

&lt;p&gt;A software engineer takes a broader, more strategic approach to building software systems. They apply engineering principles to design, develop, test, and maintain scalable and robust software solutions, &lt;strong&gt;solve complex problems&lt;/strong&gt;, manage large codebases and ensure reliability and performance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; A software engineer may design and build the entire authentication system for a platform, considering scalability, security, and maintainability. Basically creating their own version of &lt;a href="https://dev.to/haithamoumer/getting-started-with-keycloak-understanding-the-basics-55bf"&gt;Keycloak&lt;/a&gt;, but with just enough features to regret not using Keycloak in the first place.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. The Role of AI: Friend or Foe?
&lt;/h2&gt;

&lt;p&gt;AI is rapidly transforming both roles, especially tools like GitHub Copilot, Claude, and other AI coding assistants.&lt;/p&gt;

&lt;h3&gt;
  
  
  Impact on Coders
&lt;/h3&gt;

&lt;p&gt;AI can accelerate a coder's productivity by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Suggesting code completions.&lt;/li&gt;
&lt;li&gt;Writing boilerplate or repetitive code.&lt;/li&gt;
&lt;li&gt;Automating bug fixes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Impact on Software Engineers
&lt;/h3&gt;

&lt;p&gt;AI becomes a collaborator, not a replacement and :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Helps with code review and documentation.&lt;/li&gt;
&lt;li&gt;Assists in prototyping and testing.&lt;/li&gt;
&lt;li&gt;Enables focus on higher-level design and problem-solving.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The New Relationship: Coder &amp;amp; Software Engineer &amp;amp; AI
&lt;/h2&gt;

&lt;p&gt;The future of software development is about working together, not replacing people. Coders who learn to think about the bigger picture can grow into engineers, while engineers who use AI can work faster and smarter. AI boosts productivity and accuracy, but it can't replace human creativity, intuition, or deep design skills.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion:
&lt;/h2&gt;

&lt;p&gt;AI is changing how we build software, bringing coders and engineers closer together. By working with AI, everyone can get more done and focus on what matters most which is creating great software. The future is about people and AI &lt;strong&gt;working as a team&lt;/strong&gt;, not one replacing the other.&lt;/p&gt;

&lt;p&gt;The real challenge isn't to fear AI, but to learn &lt;strong&gt;how to use it effectively in your work&lt;/strong&gt;, whether you're writing code or designing complex systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;Created by &lt;a href="https://www.linkedin.com/in/haitham-oumerzoug/" rel="noopener noreferrer"&gt;OUMERZOUG Haitham&lt;/a&gt;&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>programming</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>Keycloak MCP: Simplifying Keycloak Management Through Model Context Protocol</title>
      <dc:creator>OUMERZOUG Haïtham</dc:creator>
      <pubDate>Tue, 27 May 2025 21:44:01 +0000</pubDate>
      <link>https://dev.to/haithamoumer/keycloak-mcp-simplifying-keycloak-management-through-model-context-protocol-18bh</link>
      <guid>https://dev.to/haithamoumer/keycloak-mcp-simplifying-keycloak-management-through-model-context-protocol-18bh</guid>
      <description>&lt;p&gt;Have you ever wished for a more streamlined way to manage your Keycloak users and realms? Today, I'm excited to introduce &lt;strong&gt;Keycloak MCP&lt;/strong&gt;, a Model Context Protocol server implementation that makes Keycloak management more accessible and standardized than ever before.&lt;/p&gt;

&lt;p&gt;Like i always say if you're new to Keycloak, check out my previous articles: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/haithamoumer/getting-started-with-keycloak-understanding-the-basics-55bf"&gt;&lt;strong&gt;Getting Started with Keycloak: Understanding the Basics&lt;/strong&gt;&lt;/a&gt; to understand how to set up and configure Keycloak.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/haithamoumer/secure-your-rest-api-using-keycloak-role-based-access-control-3f96"&gt;&lt;strong&gt;Secure Your RESTful API Using Keycloak Role-Based Access Control&lt;/strong&gt;&lt;/a&gt; to secure you API using RBAC.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/haithamoumer/going-deeper-with-keycloak-understanding-authorization-services-27m"&gt;&lt;strong&gt;Going Deeper with Keycloak: Understanding Authorization Services&lt;/strong&gt;&lt;/a&gt; to understand the basics of Keycloak Authorization Services and how to set up all the necessary configurations.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/haithamoumer/integrating-kc-authorization-services-into-nestjs-api-46kd"&gt;&lt;strong&gt;Integrating KC Authorization Services into NestJS API&lt;/strong&gt;&lt;/a&gt; to apply fine-grained, policy-based access control using Keycloak's authorization features inside a NestJS backend.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Foundations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is MCP (Model Context Protocol)?
&lt;/h3&gt;

&lt;p&gt;Before diving into Keycloak MCP, let's quickly understand MCP. The &lt;a href="https://modelcontextprotocol.io/introduction" rel="noopener noreferrer"&gt;Model Context Protocol (MCP)&lt;/a&gt; is a standardized communication protocol that enables AI models to interact with external tools and services. Think of it as a universal translator that allows AI models to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discover what tools are available&lt;/li&gt;
&lt;li&gt;Execute operations with proper validation&lt;/li&gt;
&lt;li&gt;Receive standardized responses&lt;/li&gt;
&lt;li&gt;Handle errors consistently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An MCP server, therefore, acts as a bridge between AI models and real-world applications, providing a structured way to expose functionality to AI systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Keycloak MCP?
&lt;/h2&gt;

&lt;p&gt;Keycloak MCP is a specialized server implementation that bridges the gap between Keycloak's administrative capabilities and the Model Context Protocol (MCP). It provides a standardized interface for managing Keycloak users and realms, making it easier to integrate Keycloak management into various development workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🚀 &lt;strong&gt;User Management&lt;/strong&gt;: Create and delete users with ease&lt;/li&gt;
&lt;li&gt;👥 &lt;strong&gt;Role Management&lt;/strong&gt;: Assign client roles to users&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Realm Operations&lt;/strong&gt;: List and manage realms effortlessly&lt;/li&gt;
&lt;li&gt;👪 &lt;strong&gt;Group Management&lt;/strong&gt;: Handle user groups efficiently&lt;/li&gt;
&lt;li&gt;🔑 &lt;strong&gt;Client Management&lt;/strong&gt;: List clients and their roles&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Available Tools
&lt;/h2&gt;

&lt;p&gt;Here's what you can do with Keycloak MCP:&lt;/p&gt;

&lt;h3&gt;
  
  
  User Management
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create new users with full profile information&lt;/li&gt;
&lt;li&gt;Delete existing users&lt;/li&gt;
&lt;li&gt;List all users in a realm&lt;/li&gt;
&lt;li&gt;Add users to groups&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Role and Client Management
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;List available realms&lt;/li&gt;
&lt;li&gt;View all clients in a realm&lt;/li&gt;
&lt;li&gt;List client roles&lt;/li&gt;
&lt;li&gt;Assign client roles to users&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Group Operations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;List all groups in a realm&lt;/li&gt;
&lt;li&gt;Manage user group memberships&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and more tools are comming...&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Node.js (Latest LTS version)&lt;/li&gt;
&lt;li&gt;npm&lt;/li&gt;
&lt;li&gt;A running Keycloak instance&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Quick Installation
&lt;/h3&gt;

&lt;p&gt;You can install Keycloak MCP in two ways:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Via Smithery (Recommended)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;-y&lt;/span&gt; @smithery/cli &lt;span class="nb"&gt;install&lt;/span&gt; @HaithamOumerzoug/keycloak-mcp &lt;span class="nt"&gt;--client&lt;/span&gt; claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Via NPM
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Direct usage with npx&lt;/span&gt;
npx &lt;span class="nt"&gt;-y&lt;/span&gt; keycloak-mcp

&lt;span class="c"&gt;# Or global installation&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; keycloak-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;To configure Keycloak MCP in your environment, add the following to your MCP configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"keycloak"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"keycloak-mcp"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"KEYCLOAK_URL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"KEYCLOAK_ADMIN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"KEYCLOAK_ADMIN_PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"admin"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Feature Demo
&lt;/h2&gt;


  
  Your browser does not support the video tag, check this url : [demo](https://github.com/user-attachments/assets/4b02a049-b8d6-4cc5-a7b4-564a0e758dd8)


&lt;h2&gt;
  
  
  Benefits of Using Keycloak MCP
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Standardization&lt;/strong&gt;: Consistent interface for Keycloak operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplification&lt;/strong&gt;: Reduces complexity in managing Keycloak&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration&lt;/strong&gt;: Easy to integrate with existing tools and workflows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation&lt;/strong&gt;: Perfect for automated user management scenarios&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer-Friendly&lt;/strong&gt;: Clean API with TypeScript support&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Technical Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;TypeScript for type safety&lt;/li&gt;
&lt;li&gt;@keycloak/keycloak-admin-client for Keycloak integration&lt;/li&gt;
&lt;li&gt;Model Context Protocol SDK for standardized communication&lt;/li&gt;
&lt;li&gt;Zod for robust schema validation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Future Development
&lt;/h2&gt;

&lt;p&gt;The project is actively maintained and welcomes contributions. Some planned features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enhanced role management capabilities&lt;/li&gt;
&lt;li&gt;Extended user management features&lt;/li&gt;
&lt;li&gt;Extended group management features&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Keycloak MCP brings a new level of simplicity to Keycloak management through standardized protocols and intuitive tooling. Whether you're managing a small application or a large enterprise system, Keycloak MCP can help streamline your identity and access management workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Coming Next?
&lt;/h2&gt;

&lt;p&gt;Stay tuned for my upcoming articles in this series where I'll cover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Real-time Updates with SSE&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implementing Server-Sent Events (SSE) communication between Keycloak MCP server and clients&lt;/li&gt;
&lt;li&gt;Setting up &lt;code&gt;/sse&lt;/code&gt; endpoints for live updates&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MCP Security Best Practices&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Secure credential management&lt;/li&gt;
&lt;li&gt;Safe storage of sensitive information&lt;/li&gt;
&lt;li&gt;Authentication and authorization patterns&lt;/li&gt;
&lt;li&gt;Environment-based configuration strategies&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These upcoming articles will help you build more robust and secure implementations with Keycloak MCP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/HaithamOumerzoug/keycloak-mcp" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://smithery.ai/server/@HaithamOumerzoug/keycloak-mcp" rel="noopener noreferrer"&gt;Smithery Package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/keycloak-mcp" rel="noopener noreferrer"&gt;NPM Package&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Stay tuned, the real fun is just getting started!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;Created by &lt;a href="https://www.linkedin.com/in/haitham-oumerzoug/" rel="noopener noreferrer"&gt;OUMERZOUG Haitham&lt;/a&gt;, Keycloak MCP is an open-source project under the MIT license.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>keycloak</category>
      <category>mcp</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Integrating KC Authorization Services into NestJS API</title>
      <dc:creator>OUMERZOUG Haïtham</dc:creator>
      <pubDate>Wed, 30 Apr 2025 22:09:32 +0000</pubDate>
      <link>https://dev.to/haithamoumer/integrating-kc-authorization-services-into-nestjs-api-46kd</link>
      <guid>https://dev.to/haithamoumer/integrating-kc-authorization-services-into-nestjs-api-46kd</guid>
      <description>&lt;p&gt;In this article, we are going to connect between Keycloak Authorization Services and a real NestJS API. After setting up all the resources, scopes, policies, and permissions in Keycloak, it's time to see it in action.&lt;br&gt;
We'll integrate Keycloak into our NestJS backend, protect specific endpoints based on permissions not just roles and test everything using Insomnia.&lt;/p&gt;

&lt;p&gt;Like i always say if you're new to Keycloak, check out my previous articles: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/haithamoumer/getting-started-with-keycloak-understanding-the-basics-55bf"&gt;&lt;strong&gt;Getting Started with Keycloak: Understanding the Basics&lt;/strong&gt;&lt;/a&gt; to understand how to set up and configure Keycloak.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/haithamoumer/secure-your-rest-api-using-keycloak-role-based-access-control-3f96"&gt;&lt;strong&gt;Secure Your RESTful API Using Keycloak Role-Based Access Control&lt;/strong&gt;&lt;/a&gt; to secure you API using RBAC.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/haithamoumer/going-deeper-with-keycloak-understanding-authorization-services-27m"&gt;&lt;strong&gt;Going Deeper with Keycloak: Understanding Authorization Services&lt;/strong&gt;&lt;/a&gt; to understand the basics of Keycloak Authorization Services and how to set up all the necessary configurations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So let's get started!&lt;/p&gt;
&lt;h2&gt;
  
  
  Application configuration
&lt;/h2&gt;

&lt;p&gt;In this article, we'll build on the API code created in the &lt;a href="https://dev.to/haithamoumer/secure-your-rest-api-using-keycloak-role-based-access-control-3f96"&gt;&lt;strong&gt;Secure Your RESTful API Using Keycloak Role-Based Access Control&lt;/strong&gt;&lt;/a&gt; article.&lt;/p&gt;

&lt;p&gt;First let's define some constants :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;resouces.ts&lt;/code&gt; :
In this file, we define a list of resources that our application will work with.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;RESOURCES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="c1"&gt;// user resource for /users/* endpoints&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;scopes.ts&lt;/code&gt;:
In this file, we define all the scopes that represent the actions users can perform on our resources.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SCOPES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;read&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;WRITE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;write&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;DELETE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now let's update our &lt;code&gt;user.controller.ts&lt;/code&gt; file to stop relying on roles and instead use fine-grained permissions with scopes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Scopes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nest-keycloak-connect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RESOURCES&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constants/resources&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SCOPES&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constants/scopes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./models/user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./user.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RESOURCES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;USER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SCOPES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WRITE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:userId/update&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SCOPES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WRITE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;userId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SCOPES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DELETE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;deleteUser&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;all&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SCOPES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;findAllUsers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findAllUsers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test in Insomnia (or Postman)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Viewer User:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frwnlx8gmh08iwbg8or2r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frwnlx8gmh08iwbg8or2r.png" alt="Viewer User" width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The viewer user, who has the &lt;code&gt;viewer&lt;/code&gt; role, is granted access only to the &lt;code&gt;/users/all&lt;/code&gt; endpoint, which is protected using the &lt;code&gt;read&lt;/code&gt; scope.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl6te469eezytr7i974ay.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl6te469eezytr7i974ay.png" alt="Viewer: Read Users" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the viewer user tries to access other endpoints, they will receive a &lt;strong&gt;Forbidden&lt;/strong&gt; error.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivxl06cydul114vmnkdd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivxl06cydul114vmnkdd.png" alt="Viewer: Create Users" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Manager User:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fopfu9d4czmourvzu5vdo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fopfu9d4czmourvzu5vdo.png" alt="Manager User" width="800" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The manager user, who has the &lt;code&gt;manager&lt;/code&gt; role, is allowed to access endpoints protected by the &lt;code&gt;read&lt;/code&gt; and &lt;code&gt;write&lt;/code&gt; scopes — like viewing all users and creating new ones.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7whs5ykkfqxa3qy1z513.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7whs5ykkfqxa3qy1z513.png" alt="Manager User : Create User" width="800" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, if the manager tries to access an endpoint that requires the &lt;strong&gt;delete&lt;/strong&gt; scope, they’ll receive a &lt;strong&gt;Forbidden&lt;/strong&gt; error.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhrjkz3ewmhccntpltrq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhrjkz3ewmhccntpltrq.png" alt="Manager User : Delete User" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Admin User:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjl4bb8bxp9rxjmu9zonj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjl4bb8bxp9rxjmu9zonj.png" alt="Admin User" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The admin user, with the &lt;code&gt;admin&lt;/code&gt; role, has full access to all user-related endpoints, including those protected by the &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;write&lt;/code&gt;, and &lt;code&gt;delete&lt;/code&gt; scopes.&lt;/p&gt;

&lt;p&gt;As expected, all authorized requests from the admin user will succeed without any Forbidden errors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6n1x4ch8u7r142f8a77.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6n1x4ch8u7r142f8a77.png" alt="Admin User: Delete User" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3r5dgok8htvrqfi7gz3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3r5dgok8htvrqfi7gz3.png" alt="Admin User: Read Users" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;And that's it! In this article, we've integrated Keycloak Authorization Services into a NestJS API and used fine-grained permissions to protect our endpoints. By replacing static role checks, we've unlocked a more powerful and flexible way to handle authorization.&lt;/p&gt;

&lt;p&gt;Now your API can enforce access rules more cleanly, and users only get access to what they truly need. Much cleaner, much safer.&lt;/p&gt;

&lt;p&gt;If you think the Keycloak series ends here, you're wrong! Next, we'll explore testing additional policy types, moving beyond just roles to enhance authorization flexibility even further.&lt;/p&gt;

&lt;p&gt;Feel free to reach out if you have questions or feedback!&lt;/p&gt;

&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;Created by &lt;a href="https://www.linkedin.com/in/haitham-oumerzoug/" rel="noopener noreferrer"&gt;OUMERZOUG Haitham&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks for reading and stay tuned!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nestjs</category>
      <category>keycloak</category>
      <category>webdev</category>
      <category>api</category>
    </item>
    <item>
      <title>Going Deeper with Keycloak: Understanding Authorization Services</title>
      <dc:creator>OUMERZOUG Haïtham</dc:creator>
      <pubDate>Tue, 22 Apr 2025 09:56:19 +0000</pubDate>
      <link>https://dev.to/haithamoumer/going-deeper-with-keycloak-understanding-authorization-services-27m</link>
      <guid>https://dev.to/haithamoumer/going-deeper-with-keycloak-understanding-authorization-services-27m</guid>
      <description>&lt;p&gt;In the first two parts of this Keycloak series, we covered the fundamentals, how to install &lt;strong&gt;Keycloak&lt;/strong&gt; and get it up and running, and how to secure your RESTful API using &lt;strong&gt;Role-Based Access Control (RBAC)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now we're going to take it one step further.&lt;br&gt;
In this article, we'll explore Keycloak Authorization Services, what they are, how they differ from simple role checks, and how to use them to define fine-grained access control using policies, permissions, and resources.&lt;/p&gt;

&lt;p&gt;If RBAC is the "&lt;em&gt;Who can do what&lt;/em&gt;", then Authorization Services answer the more complex "&lt;em&gt;Who can do what, under which conditions.&lt;/em&gt;" Let's get into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;If you've been following along, you already know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/haithamoumer/getting-started-with-keycloak-understanding-the-basics-55bf"&gt;How to install and set up Keycloak locally. &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/haithamoumer/secure-your-rest-api-using-keycloak-role-based-access-control-3f96"&gt;How to configure clients and secure a RESTful API using Role-Based Access Control.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why not just stick with RBAC?
&lt;/h2&gt;

&lt;p&gt;RBAC is a great solution for many use cases due to its simplicity, ease of implementation and understanding. You assign roles to users (like admin, user, or viewer) and control what each role can access.&lt;/p&gt;

&lt;p&gt;However, RBAC starts to show its limitations when your access control needs become more dynamic or context-aware like :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to restrict access based on ownership (users can only see/edit their own projects).&lt;/li&gt;
&lt;li&gt;You want to allow access only during certain times (like working hours).&lt;/li&gt;
&lt;li&gt;Access should depend on user attributes (like department or region).&lt;/li&gt;
&lt;li&gt;You need to apply different policies to the same role based on context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to use RBAC to handle that, you'll need to create roles like: &lt;code&gt;access-weekdays-only&lt;/code&gt;, &lt;code&gt;admin-si-department&lt;/code&gt;, &lt;code&gt;owner-or-manager-except-fridays&lt;/code&gt;. That leads to a spaghetti mess of roles, and congrats, you're accidentally reinventing what an Authorization Services was made for.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a Keycloak Authorization Services?
&lt;/h2&gt;

&lt;p&gt;The Keycloak Authorization Services is a feature in Keycloak that helps you control who can access what in your application, but in a smarter way than just using roles.&lt;/p&gt;

&lt;p&gt;It does this using four simple building blocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resources:&lt;/strong&gt; What you're protecting (page, API, file, ...).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scopes:&lt;/strong&gt; What actions someone can do (read, write, delete, ...).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policies:&lt;/strong&gt; Rules that decide who's allowed (based on roles, groups, time of day, ...).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permissions:&lt;/strong&gt; The final rule that puts everything together (combination of resources, scopes, and policies).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So instead of writing all your access rules in your app code, you manage them in Keycloak, so it' clean, organized, and easy to update.&lt;/p&gt;

&lt;p&gt;Enough talk, Let's get to the fun part. Time to switch gears and bring those permissions to life in your app!&lt;/p&gt;

&lt;h2&gt;
  
  
  Enabling Authorization on a Client
&lt;/h2&gt;

&lt;p&gt;In our demo, we'll use the same client from the previous article &lt;a href="https://dev.to/haithamoumer/secure-your-rest-api-using-keycloak-role-based-access-control-3f96"&gt;&lt;strong&gt;Secure Your RESTful API Using Keycloak Role-Based Access Control&lt;/strong&gt;&lt;/a&gt;.&lt;br&gt;
To enable authorization go to your client settings in Keycloak and:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Capability config&lt;/strong&gt; section.&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Authorization&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Save&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyf0nv3jfru7mdkmfcbwk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyf0nv3jfru7mdkmfcbwk.png" alt="Enabling Authorization" width="800" height="850"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Boooom!! Your client is now equipped to define advanced access controls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining Scopes
&lt;/h2&gt;

&lt;p&gt;Scopes in Keycloak Authorization represent what can be done to a resource. You can define scopes like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;read&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;write&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;delete&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are later used in permissions to grant access selectively.&lt;br&gt;
To create those scopes go to your client settings and :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the Authorization tab.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Scopes&lt;/strong&gt; sub-tab.&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Create authorization scope&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set the scope name, (e.g. &lt;code&gt;read&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Click on Save.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc9vcog9unh05pd4euhs2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc9vcog9unh05pd4euhs2.png" alt="Defining scope" width="800" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdvcgmt5q2gvbwhuni33a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdvcgmt5q2gvbwhuni33a.png" alt="Create read scope" width="700" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repeat the same actions for all other scopes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faoihhnkjweymrkipy0a8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faoihhnkjweymrkipy0a8.png" alt="Scopes" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining Resources
&lt;/h2&gt;

&lt;p&gt;Think of resources as the actual entities you're protecting. This could be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An API endpoint.&lt;/li&gt;
&lt;li&gt;A Web page.&lt;/li&gt;
&lt;li&gt;A Document.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;W'll create a new resource named &lt;code&gt;user&lt;/code&gt; to protect all user-related endpoints like &lt;code&gt;/users/*&lt;/code&gt;.&lt;br&gt;
To create a resource, go to your client settings and follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the Authorization tab.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Ressources&lt;/strong&gt; sub-tab.&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Create ressource&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set the resource name to something like &lt;code&gt;user&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;URI pattern&lt;/strong&gt; for user endpoints, such as &lt;code&gt;/api/users/*&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Select the previously created scopes (read,write and delete).&lt;/li&gt;
&lt;li&gt;Click on Save.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4k25b898jioc0rnsljds.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4k25b898jioc0rnsljds.png" alt="Defining Resource" width="800" height="678"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this demo, we'll use a simple role-based policy, which means access will be granted based on user roles we've already defined (like &lt;code&gt;admin&lt;/code&gt;, &lt;code&gt;manager&lt;/code&gt;, &lt;code&gt;viewer&lt;/code&gt;, etc.).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you’re not familiar with how to create a client role, feel free to check out the previous article: &lt;a href="https://dev.to/haithamoumer/secure-your-rest-api-using-keycloak-role-based-access-control-3f96"&gt;Secure Your RESTful API Using Keycloak Role-Based Access Control&lt;/a&gt;, It walks you through the process step-by-step.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To create a role-based policy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to your client settings and navigate to the Authorization tab.&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;Policies&lt;/strong&gt; sub-tab.&lt;/li&gt;
&lt;li&gt;Hit &lt;strong&gt;Create client policy&lt;/strong&gt; and select &lt;strong&gt;Role&lt;/strong&gt; as the policy type.&lt;/li&gt;
&lt;li&gt;Give your policy a meaningful name, for example:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;admin-role-policy:&lt;/strong&gt; Includes the admin role (full access).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;manager-role-policy:&lt;/strong&gt; Includes the manager role (read, create, and update access).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;viewer-role-policy:&lt;/strong&gt; Includes the viewer role (read-only access).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Under the &lt;strong&gt;Roles&lt;/strong&gt; section, select the matching role for each policy.&lt;/li&gt;
&lt;li&gt;Click Save.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxa2rvaaadxouqar1onof.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxa2rvaaadxouqar1onof.png" alt="Defining policy" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp0olyx4zyji78ummkvnv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp0olyx4zyji78ummkvnv.png" alt="policies" width="800" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Policies can be configured with &lt;strong&gt;positive&lt;/strong&gt; or &lt;strong&gt;negative&lt;/strong&gt; logic. Briefly, you can use this option to define whether the policy result should be kept as it is or be negated.&lt;/p&gt;

&lt;p&gt;For example, suppose you want to create a policy where only users not granted with a specific role should be given access. In this case, you can create a role-based policy using that role and set its Logic field to Negative. If you keep Positive, which is the default behavior, the policy result will be kept as it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining Permissions
&lt;/h2&gt;

&lt;p&gt;A permission associates the object being protected and the policies that must be evaluated to decide whether access should be granted.&lt;br&gt;
For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Allow users with manager role to edit users.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this demo, we'll create permissions associated with the defined scopes (&lt;code&gt;read&lt;/code&gt;, &lt;code&gt;write&lt;/code&gt;, and &lt;code&gt;delete&lt;/code&gt;). Permissions are used to link resources, scopes, and policies together, they define who can do what on which resource.&lt;/p&gt;

&lt;p&gt;To create a permission:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to your client's &lt;strong&gt;Authorization&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Permissions&lt;/strong&gt; sub-tab.&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Create permission&lt;/strong&gt; and choose &lt;strong&gt;Scope-Based&lt;/strong&gt; as the type.&lt;/li&gt;
&lt;li&gt;Give your permission a meaningful name (e.g., User Read Permission).&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Resources&lt;/strong&gt;, select the resource you created earlier (&lt;code&gt;user&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Scopes&lt;/strong&gt;, choose the relevant scope (&lt;code&gt;read&lt;/code&gt;, &lt;code&gt;write&lt;/code&gt;, or &lt;code&gt;delete&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Policies&lt;/strong&gt;, select the policy that matches the role allowed to perform this action (e.g., &lt;code&gt;viewer-role-policy&lt;/code&gt; for read access).&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Decision strategy&lt;/strong&gt; to &lt;strong&gt;Affirmative&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click Save.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fikqcspw84e95m8vpno39.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fikqcspw84e95m8vpno39.png" alt="Defining permission" width="800" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repeat this process for each scope and link it with the appropriate policy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;read =&amp;gt; viewer-role-policy&lt;/li&gt;
&lt;li&gt;write =&amp;gt; manager-role-policy or admin-role-policy&lt;/li&gt;
&lt;li&gt;delete =&amp;gt; admin-role-policy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fakxje0bf5nw582up07sr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fakxje0bf5nw582up07sr.png" alt="Permissions" width="800" height="265"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When associating policies with a permission, you can also define a &lt;strong&gt;decision strategy&lt;/strong&gt; to specify how to evaluate the outcome of the associated policies to determine access.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unanimous :&lt;/strong&gt; The default strategy if none is provided. In this case, all policies must evaluate to a positive decision for the final decision to be also positive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Affirmative :&lt;/strong&gt; In this case, at least one policy must evaluate to a positive decision for the final decision to be also positive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consensus :&lt;/strong&gt; In this case, the number of positive decisions must be greater than the number of negative decisions. If the number of positive and negative decisions is equal, the final decision will be negative.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This setup ensures only the right roles can perform specific actions on the user resource.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluating and Testing Policies
&lt;/h2&gt;

&lt;p&gt;When designing your policies, you can simulate authorization requests to test how your policies are being evaluated.&lt;/p&gt;

&lt;p&gt;You can access the Policy Evaluation Tool by clicking the &lt;strong&gt;Evaluate&lt;/strong&gt; tab when editing a resource server. There you can specify different inputs to simulate real authorization requests and test the effect of your policies.&lt;/p&gt;

&lt;p&gt;For example, we want to test and evaluate whether a &lt;strong&gt;viewer&lt;/strong&gt; user has access to the read scope of the user resource.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbi7f5ocqhjpivclkum1y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbi7f5ocqhjpivclkum1y.png" alt="IEvaluate Read Scope" width="800" height="621"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The  result :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fayuz790l95ocoomz5awa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fayuz790l95ocoomz5awa.png" alt="Read Scope Result" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;And that's it! You've now seen how powerful Keycloak's Authorization Services can be, no more spaghetti roles or complex permission logic scattered across your codebase. Instead, you have a clean, centralized way to manage access, based on real-world rules.&lt;/p&gt;

&lt;p&gt;In the next article, we'll take this setup and integrate it with a &lt;strong&gt;NestJS app&lt;/strong&gt;, so you can see how everything works together in action.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Stay tuned, the real fun is just getting started!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;Created by &lt;a href="https://www.linkedin.com/in/haitham-oumerzoug/" rel="noopener noreferrer"&gt;OUMERZOUG Haitham&lt;/a&gt;&lt;/p&gt;

</description>
      <category>oauth</category>
      <category>keycloak</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Secure Your RESTful API Using Keycloak Role-Based Access Control</title>
      <dc:creator>OUMERZOUG Haïtham</dc:creator>
      <pubDate>Thu, 13 Mar 2025 23:20:28 +0000</pubDate>
      <link>https://dev.to/haithamoumer/secure-your-rest-api-using-keycloak-role-based-access-control-3f96</link>
      <guid>https://dev.to/haithamoumer/secure-your-rest-api-using-keycloak-role-based-access-control-3f96</guid>
      <description>&lt;p&gt;When building a REST API, security is a top priority. One of the best ways to manage authentication and authorization is by using &lt;strong&gt;Keycloak&lt;/strong&gt;, an open-source Identity and Access Management (IAM) solution. In this guide, we will walk through how to secure a REST API using Keycloak's &lt;strong&gt;Role-Based Access Control (RBAC)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you're new to Keycloak, check out my previous article: &lt;a href="https://dev.to/haithamoumer/getting-started-with-keycloak-understanding-the-basics-55bf"&gt;&lt;strong&gt;Getting Started with Keycloak: Understanding the Basics&lt;/strong&gt;&lt;/a&gt; to understand how to set up and configure Keycloak.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Keycloak RBAC?
&lt;/h2&gt;

&lt;p&gt;Role-Based Access Control (RBAC) is a method in which users are assigned &lt;strong&gt;roles&lt;/strong&gt;, and these roles determine the &lt;strong&gt;resources&lt;/strong&gt; they can access. A resource can be a set of one or more application endpoints or a traditional web page (HTML page).&lt;/p&gt;

&lt;p&gt;By integrating this method into your RESTful API ecosystem, you can ensure that only authorized users have access to your resources and protect sensitive data.&lt;/p&gt;

&lt;p&gt;In this article, we will walk through a step-by-step process to secure a &lt;a href="https://nestjs.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Nest.js&lt;/strong&gt;&lt;/a&gt; RESTful API using Keycloak. This includes setting up an application client and configuring authentication and RBAC for your API endpoints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keycloak Configuration
&lt;/h2&gt;

&lt;p&gt;After installing Keycloak in your local environment, it's time to get started. Let's begin by creating our first realm.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Realm:
&lt;/h3&gt;

&lt;p&gt;A realm in Keycloak is an isolated environment where you manage clients, users, roles, and authentication settings. It allows multiple realms to exist independently within the same Keycloak instance.&lt;/p&gt;

&lt;p&gt;When you first enter into keycloak, a predefined realm is created. This initial realm is called the &lt;strong&gt;master&lt;/strong&gt; realm and is the king of all realms. Admins in this realm have permissions to view and manage any other realm created on the server instance. When you define your initial admin account, you are creating an account in the master realm. Your initial login to the admin console will also be through the master realm.&lt;/p&gt;

&lt;p&gt;It is recommended &lt;strong&gt;not to use&lt;/strong&gt; the master realm for managing users and applications in your organization. Instead, keep it reserved for super admins who create and manage other realms, ensuring a clean and organized setup.&lt;/p&gt;

&lt;p&gt;Now, we need to create our demo realm. To do this, hover over the dropdown menu in the top-left corner, which is labeled master, and click the &lt;code&gt;Create realm&lt;/code&gt; button (or &lt;code&gt;Add realm&lt;/code&gt; in older versions).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa5uxjqr0vlk6nl8z7ssq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa5uxjqr0vlk6nl8z7ssq.png" alt="Master Realm" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create Realm&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjd8jvurv7no9jqpz66up.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjd8jvurv7no9jqpz66up.png" alt="Create Keycloak Realm" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating your realm, you will be automatically redirected into it, and you'll be ready to proceed to the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Client:
&lt;/h3&gt;

&lt;p&gt;Clients are entities that can request user authentication. They can represent an application or a service.&lt;/p&gt;

&lt;p&gt;To create an client go to the &lt;code&gt;Clients&lt;/code&gt; left menu item. On this page you’ll see a Create button on the top.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbzou4ie67ror65um1v7l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbzou4ie67ror65um1v7l.png" alt="Create Keycloak Client" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will bring you to the &lt;code&gt;Create Client&lt;/code&gt; page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmka7tcspj1xig07r4wcv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmka7tcspj1xig07r4wcv.png" alt="Create Keycloak Client" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First step is to set the &lt;strong&gt;client name&lt;/strong&gt; and &lt;strong&gt;client id&lt;/strong&gt;. For this demo the client id is &lt;strong&gt;nestjs-sso-demo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd3s3wdh3mxcnhs3fou7i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd3s3wdh3mxcnhs3fou7i.png" alt="Create Keycloak Client" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since we have a &lt;strong&gt;server-side application&lt;/strong&gt;, we need to enable Client Authentication. This involves setting the Access Type to &lt;strong&gt;confidential&lt;/strong&gt;, which allows us to access the secret key. Leave the other options as they are.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5myxg5vge86mzz3blk8k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5myxg5vge86mzz3blk8k.png" alt="Create Keycloak Client" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last step is to set the &lt;strong&gt;URLs&lt;/strong&gt; of your application. In my case, I set the Valid Redirect URIs to &lt;code&gt;http://localhost:3000&lt;/code&gt;, which is the URL for my NestJS app. Make sure to update this with the correct URL for your app and click on &lt;code&gt;Save&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fof398jj84kxnhjxnzmqx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fof398jj84kxnhjxnzmqx.png" alt="Create Keycloak Client" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Client Roles:
&lt;/h3&gt;

&lt;p&gt;After creating the client, you will be redirected into it. Now, it's time to define the app roles.&lt;/p&gt;

&lt;p&gt;Client roles serve as granular definitions of access privileges within a specific client application or service. These roles delineate the actions and permissions that users associated with the client can perform within the application.&lt;/p&gt;

&lt;p&gt;Client roles are distinct from &lt;strong&gt;realm roles&lt;/strong&gt;, which apply globally across &lt;strong&gt;all clients within a Keycloak realm&lt;/strong&gt;. Instead, client roles are scoped to individual clients, allowing for fine-grained control over access within each application or service.&lt;/p&gt;

&lt;p&gt;To create a client role, go to the &lt;code&gt;Roles&lt;/code&gt; tab inside the client details and click on &lt;code&gt;Create role&lt;/code&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhesvctx83qv9n4qvk8i0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhesvctx83qv9n4qvk8i0.png" alt="Create Client Roles" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this demo, we will define some CRUD roles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CREATE_USER&lt;/code&gt;: Allows us to create a new user using the NestJS API.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;READ_USERS&lt;/code&gt;: Allows us to read user data.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UPDATE_USER&lt;/code&gt;: Allows us to update user data.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DELETE_USER&lt;/code&gt;: Allows us to delete user data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfg6mdapfp411yus2s37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfg6mdapfp411yus2s37.png" alt="Create Client Roles" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here we go ;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazv37jio5bitqgupjh3q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazv37jio5bitqgupjh3q.png" alt="Client Roles" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create User
&lt;/h3&gt;

&lt;p&gt;For demo purposes, we will create a demo user and assign specific roles to each one.&lt;/p&gt;

&lt;p&gt;To create an user go to the &lt;code&gt;Users&lt;/code&gt; left menu item. On this page you’ll see a &lt;code&gt;Create new user&lt;/code&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foczri2fxhduxaszbpqr1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foczri2fxhduxaszbpqr1.png" alt="Users" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first user is a viewer user with the username &lt;code&gt;read-user&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2gyore8zt97bod9jba9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2gyore8zt97bod9jba9.png" alt="Create User" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating the read-user, we will assign them the &lt;code&gt;READ_USERS&lt;/code&gt; role.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bpl0s7k8uk20zmyi4p8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bpl0s7k8uk20zmyi4p8.png" alt="Assign Role" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6emqs7zr7ao6kzmy6eu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6emqs7zr7ao6kzmy6eu.png" alt="Assign Role" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Similarly, we will create another user with the username &lt;code&gt;admin-user&lt;/code&gt; and assign all available roles to this user, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CREATE_USER&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;READ_USERS&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UPDATE_USER&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE_USER&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here we go ;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dm5czekfcwznuyqun9j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dm5czekfcwznuyqun9j.png" alt="Assign Role" width="800" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The beast has been tamed after we struggled with Keycloak configurations for some time! Now, let’s jump into the application configuration and put these roles to the test inside our NestJS app. It's time to check if all that setup was worth it!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Application Configuration
&lt;/h2&gt;

&lt;p&gt;I’m assuming you have basic knowledge of how to create a NestJS application with a basic setup. If not, no worries! You can check out the &lt;a href="https://docs.nestjs.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;NestJS documentation&lt;/strong&gt;&lt;/a&gt;, it’s very simple and easy to get started with.&lt;br&gt;
We are using &lt;strong&gt;&lt;a href="https://www.npmjs.com/package/nest-keycloak-connect" rel="noopener noreferrer"&gt;nest-keycloak-connect&lt;/a&gt;&lt;/strong&gt; &lt;strong&gt;client adapter&lt;/strong&gt; to communicate with Keycloak server.&lt;/p&gt;

&lt;p&gt;Keycloak client adapters are libraries that make it very easy to secure applications and services with Keycloak. We call these &lt;code&gt;adapters&lt;/code&gt; rather than libraries as they provide a tight integration to the underlying platform and framework. This makes adapters easy to use and require less boilerplate code than what is typically required by a library.&lt;/p&gt;
&lt;h3&gt;
  
  
  Installation:
&lt;/h3&gt;

&lt;p&gt;First let install those libraries&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i @nestjs/config keycloak-connect nest-keycloak-connect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Usage:
&lt;/h3&gt;

&lt;p&gt;We need to add Keycloak configuration to Nest.js.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Module&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ConfigModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ConfigService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nestjs/config&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;APP_GUARD&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nestjs/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;AuthGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;KeycloakConnectConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;KeycloakConnectModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ResourceGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;RoleGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nest-keycloak-connect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppController&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./app.controller&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./app.service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./user/user.module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;ConfigModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;isGlobal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nx"&gt;KeycloakConnectModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerAsync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ConfigService&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;useFactory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;configService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ConfigService&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;KeycloakConnectConfig&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;authServerUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;configService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;KC_AUTH_SERVER_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;realm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;configService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;KC_REALM&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;configService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;KC_CLIENT_ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;configService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;KC_SECRET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;useNestLogger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nx"&gt;UserModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;controllers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppController&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;AppService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// This adds a global level authentication guard,&lt;/span&gt;
    &lt;span class="c1"&gt;// you can also have it scoped&lt;/span&gt;
    &lt;span class="c1"&gt;// if you like.&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="c1"&gt;// Will return a 401 unauthorized when it is unable to&lt;/span&gt;
    &lt;span class="c1"&gt;// verify the JWT token or Bearer header is missing.&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APP_GUARD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AuthGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// This adds a global level resource guard, which is permissive.&lt;/span&gt;
    &lt;span class="c1"&gt;// Only controllers annotated with @Resource and&lt;/span&gt;
    &lt;span class="c1"&gt;// methods with @Scopes&lt;/span&gt;
    &lt;span class="c1"&gt;// are handled by this guard.&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APP_GUARD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ResourceGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// New in 1.1.0&lt;/span&gt;
    &lt;span class="c1"&gt;// This adds a global level role guard, which is permissive.&lt;/span&gt;
    &lt;span class="c1"&gt;// Used by `@Roles` decorator with the&lt;/span&gt;
    &lt;span class="c1"&gt;// optional `@AllowAnyRole` decorator for allowing any&lt;/span&gt;
    &lt;span class="c1"&gt;// specified role passed.&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APP_GUARD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RoleGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are using nest-keycloak-connect’s &lt;strong&gt;AuthGuard&lt;/strong&gt;, &lt;strong&gt;ResourceGuard&lt;/strong&gt; and &lt;strong&gt;RoleGuard&lt;/strong&gt; to protect our endpoints.&lt;/p&gt;

&lt;p&gt;For the environment variables :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;KC_AUTH_SERVER_URL=http://localhost:8080/ # Keycloak Instance
KC_REALM=DEMO
KC_CLIENT_ID=nestjs-sso-demo
KC_SECRET=Pvbc37M7ThncsenGa71Xrj52eLLLHsM2 # Client secret from `Credentials` tab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we add following endpoints to our User Controller.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./user.service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./models/user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Roles&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nest-keycloak-connect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ROLES&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./models/roles.enum&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;create&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Roles&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ROLES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CREATE_USER&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:userId/update&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Roles&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ROLES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UPDATE_USER&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nf"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;userId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;delete/:id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Roles&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ROLES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DELETE_USER&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nf"&gt;deleteUser&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;all&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Roles&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ROLES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;READ_USERS&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nf"&gt;findAllUsers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findAllUsers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, we’ll create a simple "Hello World" endpoint inside the App Controller that does not require authentication, using the &lt;code&gt;@Unprotected&lt;/code&gt; decorator (&lt;em&gt;You can also use &lt;code&gt;@AllowAnyRole&lt;/code&gt; decorator that allow access for any role.&lt;/em&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Get&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./app.service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Unprotected&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nest-keycloak-connect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;appService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Unprotected&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nf"&gt;getHello&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHello&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Endpoint Tests
&lt;/h3&gt;

&lt;p&gt;After setting up our endpoints, it's time to test them using &lt;strong&gt;Insomnia&lt;/strong&gt; or any API tool.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Admin User:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, we tested accessing the endpoint to create a new user, using the &lt;code&gt;admin-user&lt;/code&gt; attached with the JWT token in the Authorization header.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fql5bc6jf8jre38h2aonv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fql5bc6jf8jre38h2aonv.png" alt="API Call Create User" width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Same for update or delete user and read all users.&lt;/p&gt;

&lt;p&gt;Get all users:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft9t8cjphmnveqqd5vmfj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft9t8cjphmnveqqd5vmfj.png" alt="API Call Read Users" width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Update User:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhsaa0hj1fcdmmis3ebh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhsaa0hj1fcdmmis3ebh.png" alt="API Call Update User" width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Viewer User:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The viewer user has only the &lt;code&gt;READ_USERS&lt;/code&gt; role, which gives them access to the &lt;code&gt;/api/users/all&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foa516mv1h004vytf83a6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foa516mv1h004vytf83a6.png" alt="API Call Read Users" width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, if the same user tries to access other protected endpoints, such as the create user endpoint, the Keycloak guard will throw a &lt;strong&gt;forbidden error&lt;/strong&gt;. This means the user doesn't have the necessary permissions to access that ressource.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdf4wko4h4xp77mftfo1s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdf4wko4h4xp77mftfo1s.png" alt="Forbidden" width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Using Keycloak with RBAC makes securing your REST API easy and scalable. You can manage users, roles, and permissions &lt;strong&gt;without hardcoding them into your application&lt;/strong&gt;. By following this guide, you have set up authentication and role-based authorization for your API.&lt;/p&gt;

&lt;p&gt;However, RBAC has some limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resources and roles are tightly coupled, meaning changes to roles can impact multiple resources.&lt;/li&gt;
&lt;li&gt;Security requirement changes may require deep modifications to application code.&lt;/li&gt;
&lt;li&gt;Managing roles in large applications can become complex and error-prone.&lt;/li&gt;
&lt;li&gt;RBAC lacks contextual information, means that if you have a role, you have access, regardless of the specific context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our next article, we will explore &lt;strong&gt;Keycloak Authorization Services&lt;/strong&gt;, which provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fine-grained authorization policies and various access control mechanisms.&lt;/li&gt;
&lt;li&gt;Centralized resource, permission, and policy management.&lt;/li&gt;
&lt;li&gt;REST security using Keycloak’s authorization services.&lt;/li&gt;
&lt;li&gt;An infrastructure to reduce code replication and quickly adapt to security changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;Created by &lt;a href="https://www.linkedin.com/in/haitham-oumerzoug/" rel="noopener noreferrer"&gt;OUMERZOUG Haitham&lt;/a&gt;&lt;/p&gt;

</description>
      <category>oauth</category>
      <category>keycloak</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Getting Started with Keycloak: Understanding the Basics</title>
      <dc:creator>OUMERZOUG Haïtham</dc:creator>
      <pubDate>Thu, 09 Jan 2025 21:07:41 +0000</pubDate>
      <link>https://dev.to/haithamoumer/getting-started-with-keycloak-understanding-the-basics-55bf</link>
      <guid>https://dev.to/haithamoumer/getting-started-with-keycloak-understanding-the-basics-55bf</guid>
      <description>&lt;p&gt;In today's interconnected digital landscape, securing APIs (Application Programming Interfaces) is paramount. APIs serve as the gateway for communication between different software applications, enabling seamless data exchange. However, with this connectivity comes the risk of unauthorized access, data breaches, and other security threats.&lt;/p&gt;

&lt;p&gt;Enter Keycloak - an open-source identity and access management solution that provides robust security for your APIs and applications. Developed by &lt;strong&gt;&lt;a href="https://www.redhat.com/" rel="noopener noreferrer"&gt;Red Hat&lt;/a&gt;&lt;/strong&gt;, Keycloak simplifies user authentication, authorization, and user management, allowing you to focus on building and deploying your applications with confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keycloak Architecture
&lt;/h2&gt;

&lt;p&gt;Keycloak is a flexible and scalable identity and access management solution that provides a single point of access for all your applications. It offers a wide range of features, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User registration and management&lt;/li&gt;
&lt;li&gt;User authentication and authorization&lt;/li&gt;
&lt;li&gt;Role-based access control&lt;/li&gt;
&lt;li&gt;Social login integration&lt;/li&gt;
&lt;li&gt;Single sign-on (SSO) and single log-out (SLO)&lt;/li&gt;
&lt;li&gt;API security&lt;/li&gt;
&lt;li&gt;API management&lt;/li&gt;
&lt;li&gt;Real-time event monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wyjr3ij5uc6hap1bpcp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wyjr3ij5uc6hap1bpcp.png" alt="Keycloak Basic Architecture" width="800" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Description of the Diagram:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;User:&lt;/strong&gt; Represents the end-user interacting with the system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keycloak:&lt;/strong&gt; The central authentication server managing user sessions and authentication flows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identity Providers:&lt;/strong&gt; External systems like Google, Facebook, or LDAP used for federated identity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Applications:&lt;/strong&gt; The apps (frontend and backend) that integrate with Keycloak for authentication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keycloak Database:&lt;/strong&gt; The storage system for Keycloak, holding user data, configurations, and session information.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Keycloak Components
&lt;/h2&gt;

&lt;p&gt;Keycloak is composed of several components that work together to provide a comprehensive identity and access management solution. These components include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keycloak Server&lt;/strong&gt;: The core component of Keycloak, responsible for user authentication, authorization, and user management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keycloak Admin Console&lt;/strong&gt;: A web-based user interface for managing Keycloak, including user registration, authentication, and authorization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keycloak Realm Management&lt;/strong&gt;: A web-based user interface for managing Keycloak realms, which are logical groupings of users, applications, and other resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keycloak Client Management&lt;/strong&gt;: A web-based user interface for managing Keycloak clients, which represents an application or service that interacts with the Keycloak server for authentication and authorization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keycloak REST API&lt;/strong&gt;: A RESTful API for managing Keycloak, including user registration, authentication, and authorization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keycloak JavaScript Adapter&lt;/strong&gt;: A JavaScript library for integrating Keycloak with web applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keycloak Node.js Adapter&lt;/strong&gt;: A Node.js library for integrating Keycloak with Node.js applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keycloak Docker Image&lt;/strong&gt;: A Docker image for running Keycloak in a containerized environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Keycloak Installation: A Step-by-Step Guide
&lt;/h2&gt;

&lt;p&gt;Keycloak is an open-source Identity and Access Management (IAM) solution that simplifies securing applications and services with features like Single Sign-On (SSO), social login, and more. You can install Keycloak using various methods, including direct installation, Docker, and Docker Compose. Below, I'll explain the steps for each method.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Installing Keycloak Locally
&lt;/h3&gt;

&lt;p&gt;To install Keycloak locally, you typically need to download the Keycloak server distribution.&lt;/p&gt;

&lt;h4&gt;
  
  
  Steps to Install Keycloak Locally:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Download Keycloak :&lt;br&gt;
Go to the &lt;a href="https://www.keycloak.org/downloads-archive.html" rel="noopener noreferrer"&gt;Keycloak Downloads&lt;/a&gt; page and download the latest version of Keycloak &lt;em&gt;(Distribution powered by Quarkus)&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Extract the Archive :&lt;br&gt;
Extract the downloaded files to a directory of your choice.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xvf&lt;/span&gt; keycloak-&amp;lt;version&amp;gt;.tar.gz
&lt;span class="nb"&gt;cd &lt;/span&gt;keycloak-&amp;lt;version&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start Keycloak :&lt;br&gt;
We used the &lt;code&gt;start-dev&lt;/code&gt; command to start the Keycloak server in development mode. This command starts the server with the default configuration to try out Keycloak for the first time to get it up and running quickly.&lt;br&gt;
In the command below, we used the &lt;code&gt;--bootstrap-admin-username&lt;/code&gt; and &lt;code&gt;--bootstrap-admin-password&lt;/code&gt; options to specify the username and password for the default administrator account. You can change these values to match your requirements.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/kc.sh start-dev &lt;span class="nt"&gt;--bootstrap-admin-username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;admin &lt;span class="nt"&gt;--bootstrap-admin-password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not use this configuration in production. Instead, use the &lt;code&gt;start&lt;/code&gt; command to start the server with a custom configuration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For more information on the &lt;code&gt;start-dev&lt;/code&gt; command and other available commands, refer to the &lt;a href="https://www.keycloak.org/server/configuration" rel="noopener noreferrer"&gt;Keycloak Server Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Installing Keycloak with Docker
&lt;/h3&gt;

&lt;p&gt;Keycloak can also be installed using Docker, a containerization platform that simplifies the deployment and management of applications. Docker allows you to package your application and its dependencies into a container, which can then be deployed and run on any system that has Docker installed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Steps to Install Keycloak with Docker:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Install Docker:&lt;br&gt;
Follow the official Docker documentation to install Docker on your system. You can find the installation instructions for your operating system &lt;a href="https://docs.docker.com/engine/install/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pull the Keycloak Docker Image:&lt;br&gt;
To pull the Keycloak Docker image, run the following command:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull quay.io/keycloak/keycloak:26.0.7
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the Docker Container:&lt;br&gt;
To run the Keycloak Docker container, use the following command:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;KC_BOOTSTRAP_ADMIN_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;admin &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;KC_BOOTSTRAP_ADMIN_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;admin quay.io/keycloak/keycloak:26.0.7 start-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br&gt;
This command starts the Keycloak container and maps port 8080 on the host machine to port 8080 in the container. It also sets the &lt;code&gt;KC_BOOTSTRAP_ADMIN_USERNAME&lt;/code&gt; and &lt;code&gt;KC_BOOTSTRAP_ADMIN_PASSWORD&lt;/code&gt; environment variables to &lt;code&gt;admin&lt;/code&gt; and &lt;code&gt;admin&lt;/code&gt;, respectively.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Access the Keycloak Admin Console:&lt;br&gt;
Once the container is running, you can access the Keycloak Admin Console by opening your web browser and navigating to &lt;code&gt;http://localhost:8080/&lt;/code&gt;. You will be prompted to enter the username and password for the &lt;code&gt;admin&lt;/code&gt; user.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: You can replace &lt;code&gt;26.0.7&lt;/code&gt; with the desired version of Keycloak.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we explored the basics of Keycloak, a powerful identity and access management solution. We covered the architecture of Keycloak, its components, and how to install it locally and with Docker. The next article will dive deeper into the features and capabilities of Keycloak, including users, clients, roles, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.keycloak.org/documentation.html" rel="noopener noreferrer"&gt;Keycloak Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/keycloak/keycloak" rel="noopener noreferrer"&gt;Keycloak GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://quay.io/repository/keycloak/keycloak" rel="noopener noreferrer"&gt;Keycloak Docker Image&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;Created by &lt;a href="https://www.linkedin.com/in/haitham-oumerzoug/" rel="noopener noreferrer"&gt;OUMERZOUG Haitham&lt;/a&gt;&lt;/p&gt;

</description>
      <category>keycloak</category>
      <category>oauth</category>
      <category>openidconnect</category>
      <category>restapi</category>
    </item>
  </channel>
</rss>
