<?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>Forem: Mohammed O. Tillawy</title>
    <description>The latest articles on Forem by Mohammed O. Tillawy (@tillawy).</description>
    <link>https://forem.com/tillawy</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%2F213469%2F0f116069-903d-441f-88ea-4de639c03103.jpeg</url>
      <title>Forem: Mohammed O. Tillawy</title>
      <link>https://forem.com/tillawy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/tillawy"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Mohammed O. Tillawy</dc:creator>
      <pubDate>Sun, 23 Feb 2025 17:06:45 +0000</pubDate>
      <link>https://forem.com/tillawy/-30j6</link>
      <guid>https://forem.com/tillawy/-30j6</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/silviaodwyer" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F615824%2Facd0a505-ea02-4d7c-8aaa-360ae7ba53f0.jpeg" alt="silviaodwyer"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/silviaodwyer/10-open-source-documentation-frameworks-to-check-out-331f" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;10 Open-Source Documentation Frameworks to Check Out&lt;/h2&gt;
      &lt;h3&gt;Silvia O'Dwyer ・ Feb 21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#documentation&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#opensource&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>documentation</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Rails and Keycloak, Authentication, Authorization, part three</title>
      <dc:creator>Mohammed O. Tillawy</dc:creator>
      <pubDate>Sat, 17 Aug 2024 17:44:09 +0000</pubDate>
      <link>https://forem.com/tillawy/rails-and-keycloak-authentication-authorization-part-three-n4g</link>
      <guid>https://forem.com/tillawy/rails-and-keycloak-authentication-authorization-part-three-n4g</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/tillawy/rails-and-keycloak-authentication-authorization-part-one-cd5"&gt;part one&lt;/a&gt;, we have discussed what Keycloak is.&lt;br&gt;
In &lt;a href="https://dev.to/tillawy/rails-and-keycloak-authentication-authorization-part-two-25cg"&gt;part two&lt;/a&gt;, we have setup our Rails application to use Keycloak for authentication.&lt;br&gt;
In the third part, we will use Keycloak as a an extra security later to provide authorization checks for our API requests.&lt;/p&gt;
&lt;h2&gt;
  
  
  How does it work
&lt;/h2&gt;

&lt;p&gt;This gem is a simple middle-ware that intercepts and filters the API requests before they are processed by the application.&lt;/p&gt;

&lt;p&gt;Let us start with adding the &lt;a href="https://github.com/tillawy/rails_keycloak_authorization" rel="noopener noreferrer"&gt;gem rails_keycloak_authorization&lt;/a&gt; to our &lt;code&gt;Gemfile&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Gemfile&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"rails_keycloak_authorization"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gem initializer &lt;code&gt;config/initializers/rails_keycloak_authorization.rb&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# initializers/rails_keycloak_authorization.rb &lt;/span&gt;

&lt;span class="c1"&gt;# initializers/rails_keycloak_authorization.rb &lt;/span&gt;

&lt;span class="c1"&gt;# the realm that contains the open-client client&lt;/span&gt;
&lt;span class="no"&gt;RailsKeycloakAuthorization&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keycloak_auth_client_realm_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"KEYCLOAK_AUTH_CLIENT_REALM_NAME"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"dummy"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# the subject open-id client containing&lt;/span&gt;
&lt;span class="no"&gt;RailsKeycloakAuthorization&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keycloak_auth_client_id&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"KEYCLOAK_AUTH_CLIENT_ID"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"dummy-client"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# keycloak server_url&lt;/span&gt;
&lt;span class="no"&gt;RailsKeycloakAuthorization&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keycloak_server_url&lt;/span&gt;             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"KEYCLOAK_SERVER_URL"&lt;/span&gt;&lt;span class="p"&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="c1"&gt;# keycloak server_domain&lt;/span&gt;
&lt;span class="no"&gt;RailsKeycloakAuthorization&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keycloak_server_domain&lt;/span&gt;          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"KEYCLOAK_ADMIN_SERVER_DOMAIN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"localhost"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# keycloak realm that contains the admin-client&lt;/span&gt;
&lt;span class="no"&gt;RailsKeycloakAuthorization&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keycloak_admin_realm_name&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"KEYCLOAK_ADMIN_REALM_NAME"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"master"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# keycloak admin_client &lt;/span&gt;
&lt;span class="no"&gt;RailsKeycloakAuthorization&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keycloak_admin_client_id&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"KEYCLOAK_ADMIN_CLIENT_ID"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"keycloak-admin"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# keycloak admin_client's secret&lt;/span&gt;
&lt;span class="no"&gt;RailsKeycloakAuthorization&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keycloak_admin_client_secret&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"KEYCLOAK_ADMIN_CLIENT_SECRET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"keycloak-admin-client-secret-xxx"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# List of regext for pattern to protect&lt;/span&gt;
&lt;span class="no"&gt;RailsKeycloakAuthorization&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match_patterns&lt;/span&gt;                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="sr"&gt;/^\/organizations\.json/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sr"&gt;/^\/api\/projects/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sr"&gt;/^\/secrets\.json/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sr"&gt;/^\/api\/secrets/&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will add the UI tool, this part is not mandatory, but it will ease the setup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;mount&lt;/span&gt; &lt;span class="no"&gt;RailsKeycloakAuthorization&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;at: &lt;/span&gt;&lt;span class="s2"&gt;"/rka"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;constraints: &lt;/span&gt;&lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remote_ip&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"127.0.0.1"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# Please make sure to secure this route, for the purposes of this tutorial, I will secure it by forcing the remote_ip to be localhost.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please make sure to restart the server.&lt;br&gt;
Now open the &lt;a href="http://localhost:3000/rka/" rel="noopener noreferrer"&gt;Rails Keycloak Authorization Helper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4zcecsm3gmtkqzp6i1x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4zcecsm3gmtkqzp6i1x.png" alt="Image description" width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This tool consists of four tabs:&lt;/p&gt;

&lt;p&gt;1 - Rails routes&lt;br&gt;
In this tab we: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Map Rails controller into Keycloak Authorization Resources&lt;/li&gt;
&lt;li&gt;Map Rails controller actions to scopes.&lt;/li&gt;
&lt;li&gt;Attach Keycloak scopes to Keycloak resources &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2 - Keycloak Policies&lt;br&gt;
In this tab we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create policies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3 - Keycloak Permissions&lt;br&gt;
In this tab web:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Attach Policies to Resources. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;4 - Keycloak Resource&lt;br&gt;
You can skip this tab for now, it is work in progress.&lt;/p&gt;

&lt;p&gt;So let us do the following:&lt;/p&gt;

&lt;p&gt;Setup Routes: SecretsController#index only for managers.&lt;/p&gt;

&lt;p&gt;We will:&lt;br&gt;
1 - Create Keycloak resource: secrets_controller&lt;br&gt;
2 - Create Keycloak scope: index&lt;br&gt;
3 - Attach (scope: index) to (resource: secrets_controller)&lt;br&gt;
3 - Create Policy: RKA-Policy-Managment for role: management-client-role&lt;br&gt;
4 - Create Permission: (Policy: RKA-Policy-Managment) + (Resource: secrets_controller) + (Scope: index)&lt;br&gt;
5 - Validate our setup&lt;/p&gt;

&lt;p&gt;Let us do it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Select tab: Rails Routes&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first route /secret(.:format), click inspect&lt;/li&gt;
&lt;li&gt;click: Create Resource?&lt;/li&gt;
&lt;li&gt;click: Create Scope?&lt;/li&gt;
&lt;li&gt;click: Attach scope index to resource?&lt;/li&gt;
&lt;li&gt;click: Close &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select tab: Keycloak Policies&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the Name type: RKA-Policy-Management&lt;/li&gt;
&lt;li&gt;From the Role drop-down list select: management-client-role&lt;/li&gt;
&lt;li&gt;Click Create&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select tab: Keycloak Permissions&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From the drop-down list Policy select: RKA-Policy-Management&lt;/li&gt;
&lt;li&gt;From the drop-down list Resource select: secrets_controller&lt;/li&gt;
&lt;li&gt;From the drop-down Scope Select: index&lt;/li&gt;
&lt;li&gt;Click Create&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now it is time to test it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="nb"&gt;readonly &lt;/span&gt;&lt;span class="nv"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"manager@test.com"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;readonly &lt;/span&gt;&lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"secret"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;get_access_token &lt;span class="o"&gt;{&lt;/span&gt;
curl &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'client_id=dummy-client'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'client_secret=dummy-client-super-secret-xxx'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"username=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;username&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"password=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'grant_type=password'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'response_type=code'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'scope=openid'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s1"&gt;'http://localhost:8080/realms/dummy/protocol/openid-connect/token'&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.access_token'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;access_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;get_access_token&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;readonly &lt;/span&gt;&lt;span class="nv"&gt;url1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:3000/secrets.json"&lt;/span&gt;
&lt;span class="nb"&gt;echo &lt;/span&gt;requesting &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;url1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: bearer &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;access_token&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;url1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see the input: &lt;code&gt;[]%&lt;/code&gt;, setup is good.&lt;/p&gt;

&lt;p&gt;You can find the source for this project in this &lt;a href="https://github.com/tillawy/rails_keycloak_authorization_demo" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find the docker-compose &amp;amp; tofu setup in this &lt;a href="https://github.com/tillawy/rails_keycloak_authorization/" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can watch this video for quick walk through:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/sFCmk65n-jY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>keycloak</category>
      <category>rails</category>
    </item>
    <item>
      <title>Rails and Keycloak, Authentication, Authorization, part two</title>
      <dc:creator>Mohammed O. Tillawy</dc:creator>
      <pubDate>Sat, 17 Aug 2024 07:11:09 +0000</pubDate>
      <link>https://forem.com/tillawy/rails-and-keycloak-authentication-authorization-part-two-25cg</link>
      <guid>https://forem.com/tillawy/rails-and-keycloak-authentication-authorization-part-two-25cg</guid>
      <description>&lt;p&gt;In the second part, let us setup Keycloak authentication with Rails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run Keycloak
&lt;/h2&gt;

&lt;p&gt;First let us run Keycloak with some boilerplate setup.&lt;/p&gt;

&lt;p&gt;Please run Keycloak on docker, please use the docker-compose.yml from the following repository to save time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# checkout this repo&lt;/span&gt;
git clone https://github.com/tillawy/rails_keycloak_authorization.git
&lt;span class="nb"&gt;cd &lt;/span&gt;rails_keycloak_authorization/docker
docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous step should run &lt;a href="https://dev.tolocalhost:8080/"&gt;Keycloak on port 8080&lt;/a&gt;.&lt;br&gt;
Credentials: Username=admin, password=admin &lt;/p&gt;

&lt;p&gt;Let us use opentofu to setup keycloak.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# if you don't have opentofu&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;opentofu
rails_keycloak_authorization/tofu
tofu apply &lt;span class="nt"&gt;-var-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./secrets.tfvars &lt;span class="nt"&gt;-auto-approve&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous steps should create:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keycloak Realm, called (Dummy)&lt;/li&gt;
&lt;li&gt;Keycloak admin client with a secret with necessary roles and access&lt;/li&gt;
&lt;li&gt;Keycloak client with a secret for our application&lt;/li&gt;
&lt;li&gt;couple of users, groups and roles to do our tests&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Our Rails project
&lt;/h2&gt;

&lt;p&gt;Let us create our project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rails new ./rails_keycloak_authorization_demo --database=sqlite3
cd rails_keycloak_authorization_demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let us create our User model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bin/rails generate model User
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let us change the migration to use UUID instead of int for id:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vim ./db/migrate/*_create_users.rb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ./db/migrate/*_create_users.rb

class CreateUsers &amp;lt; ActiveRecord::Migration[7.2]
  def change
    create_table :users, id: false do |t|
      t.primary_key :id, :string, default: -&amp;gt; { "lower(hex(randomblob(16)))" }
      t.string :email, null: false, index: { unique: true }
      t.string :first_name
      t.string :last_name

      t.timestamps
    end
  end
end

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

&lt;/div&gt;



&lt;p&gt;Now let us scaffold couple of models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bin/rails generate scaffold Project name:string
bin/rails generate scaffold Secret name:string
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now migrate changes to database&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bin/rails db:migrate 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let us run the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bin/rails s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let us check that our server is up &amp;amp; running using the following links: &lt;a href="http://localhost:3000/secrets" rel="noopener noreferrer"&gt;secrets&lt;/a&gt;, &lt;a href="http://localhost:3000/projects" rel="noopener noreferrer"&gt;projects&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Keycloak &amp;amp; Rails &amp;amp; Omniauth setup
&lt;/h2&gt;

&lt;p&gt;Let us add the gems&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Gemfile
gem "omniauth"
gem "omniauth-keycloak"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let us create an initialize &lt;code&gt;config/initializers/omniauth.rb&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :keycloak_openid, ENV.fetch("KEYCLOAK_AUTH_CLIENT_ID", "dummy-client"),
  ENV.fetch("KEYCLOAK_AUTH_CLIENT_SECRET", "dummy-client-super-secret-xxx"),
  client_options: {
    site: ENV.fetch("KEYCLOAK_SERVER_URL", "http://localhost:8080"),
    realm: ENV.fetch("KEYCLOAK_AUTH_CLIENT_REALM_NAME", "dummy"),
    raise_on_failure: true,
    base_url: ""
  },
  name: "keycloak",
  provider_ignores_state: true
end

OmniAuth.config.logger = Rails.logger

OmniAuth.config.path_prefix = ENV.fetch("KEYCLOAK_AUTH_SERVER_PATH_PREFIX", "/oauth")

OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE if Rails.env.development?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure your restart your Rails server after creating this initializer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/rails s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;let us add omniauth-keycloak routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# config/routes.rb
# assume any user visiting root / needs to authenticate
get "/", to: "oauth#new"
# callbacks from keycloak handling 
get "/oauth/:provider/callback", to: "oauth#create"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let us create the controller to handle our OAuth requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class OauthController &amp;lt; ApplicationController

  # to initiate the login process,
  # We will redirect the user to Keycloak with the parameter: redirect_uri
  # the user will be redirected to keycloak, and upon success redirected back to the application

  def new
    port_str = [80, 443].include?(request.port.to_i) ? "" : ":" + request.port.to_s
    redirect_uri = "#{request.scheme}://#{request.host}#{port_str}/oauth/keycloak/callback"
    redirect_uri_escaped = CGI.escape(redirect_uri)
    client_id =  ENV.fetch("KEYCLOAK_CLIENT_ID", "dummy-client")
    realm = ENV.fetch("KEYCLOAK_REALM", "dummy" )
    auth_server_url = ENV.fetch("KEYCLOAK_AUTH_SERVER_URL", "http://localhost:8080" )
    to = "#{auth_server_url}/realms/#{realm}/protocol/openid-connect/auth?response_type=code&amp;amp;client_id=#{client_id}&amp;amp;redirect_uri=#{redirect_uri_escaped}&amp;amp;login=true&amp;amp;scope=openid"
    redirect_to to, allow_other_host: true
  end

  # final callback from keycloak
  # the user is redirected back from keycloak with the user object in request.env

  def create
    current_user = User.find_or_create_by(id: auth_hash.extra.raw_info.sub, email: auth_hash.info.email, first_name: auth_hash.info.first_name, last_name: auth_hash.info.last_name)

    session[:current_user_id] = current_user.id
    redirect_to projects_path
  end

  protected

  def auth_hash
    auth = request.env["omniauth.auth"]
    raise 'NotAuthenticatedError' unless auth

    auth
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need a Rails concern to authenticate users on controllers&lt;br&gt;
Please create the concern file &lt;code&gt;app/controllers/concerns/with_current_user.rb&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# app/controllers/concerns/with_current_user.rb

module WithCurrentUser
  extend ActiveSupport::Concern
  included do
    before_action :authenticate_user!

    def authenticate_user!
      raise "NotAuthenticatedError" unless current_user
    end

    def current_user
      current_jwt_user(nil_on_failure: true) || (session[:current_user_id] &amp;amp;&amp;amp; User.find(session[:current_user_id]))
    end

    def user_with(id:, email:, first_name:, last_name:)
      upsert = User.upsert({ id: id, email: email, first_name: first_name, last_name: last_name }, unique_by: :id)
      User.find(upsert.first["id"])
    end

    def jwk_user_from(jwt:)
      jwk_loader = -&amp;gt;(options) do
        @cached_keys = nil if options[:invalidate] # need to reload the keys
        return @cached_keys if @cached_keys

        keycloak = ENV.fetch("KEYCLOAK_AUTH_SERVER_URL", "http://localhost:8080")
        realm = ENV.fetch("KEYCLOAK_REALM", "dummy")
        uri = URI("#{keycloak}/realms/#{realm}/protocol/openid-connect/certs")
        req = Net::HTTP::Get.new uri
        res = Rails.cache.fetch("jwk_loader-certs") do
          Net::HTTP.start(uri.host, uri.port, open_time: 1, read_timeout: 1, write_timeout: 1) { |http| http.request(req) }
        end
        unless res.is_a?(Net::HTTPSuccess)
          logger.warn res.body
          raise "JWKS #{uri} FAILED"
        end
        @cached_keys ||= JSON.parse res.body
      end

      decoded = JWT.decode(jwt, nil, !Rails.env.test?, { algorithms: [ "RS256" ], jwks: jwk_loader })

      email = decoded[0]["email"] || decoded[0]["preferred_username"]
      id = decoded[0]["sub"]
      logger.debug("found (email:#{email}, id: #{id})")
      { email: email, id: id, first_name: decoded[0]["given_name"], last_name: decoded[0]["family_name"] }
    end

    def extract_token_from(headers:)
      header = headers["Authorization"]
      header&amp;amp;.split(" ")&amp;amp;.last
    end

    def current_jwt_user(nil_on_failure: false)
      return nil unless request.authorization&amp;amp;.downcase&amp;amp;.start_with?("bearer ")

      token = extract_token_from(headers: request.headers)
      begin
        user = jwk_user_from(jwt: token)
        user_with(email: user[:email], id: user[:id], first_name: user[:first_name], last_name: user[:last_name])
      rescue ActiveRecord::RecordNotFound =&amp;gt; e
        logger.error("User NOT found in DB, make sure to run Kafka consumer")
        return nil if nil_on_failure
        raise e
      rescue JWT::JWKError =&amp;gt; e
        logger.info "ApplicationController current_jwt_user JWT::JWKError " + e.message
        return nil if nil_on_failure
        raise e
      rescue JWT::DecodeError =&amp;gt; e
        logger.info "ApplicationController current_jwt_user JWT::DecodeError " + e.message
        return nil if nil_on_failure
        raise e
      end
    end
  end
end

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

&lt;/div&gt;



&lt;p&gt;We will enforce authentication on the controllers level, we will use the concern in the controllers &lt;code&gt;include WithCurrentUser&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;file: &lt;code&gt;app/controllers/projects_controller.rb&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ProjectsController &amp;lt; ApplicationController
  before_action :set_project, only: %i[ show edit update destroy ]
  include WithCurrentUser   # &amp;lt;!--- Add this line

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

&lt;/div&gt;



&lt;p&gt;file: &lt;code&gt;app/controllers/secrets_controller.rb&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class SecretsController &amp;lt; ApplicationController
  before_action :set_secret, only: %i[ show edit update destroy ]
  include WithCurrentUser   # &amp;lt;!--- Add this line

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

&lt;/div&gt;



&lt;p&gt;Let us test our setup:&lt;/p&gt;

&lt;p&gt;Please open &lt;a href="http://localhost:3000/" rel="noopener noreferrer"&gt;link&lt;/a&gt;, you should be redirected to Keyloak, &lt;br&gt;
Authenticate using username: &lt;a href="mailto:test@test.com"&gt;test@test.com&lt;/a&gt;, password: test.&lt;br&gt;
You should be redirect to back to the &lt;a href="http://localhost:3000/projects" rel="noopener noreferrer"&gt;http://localhost:3000/projects&lt;/a&gt;.&lt;br&gt;
You should see: Welcome tester&lt;/p&gt;

&lt;p&gt;Let us test our project using curl / JWT&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash

readonly username="employee@test.com";
readonly password="secret";

function get_access_token {
curl --silent \
    -d 'client_id=dummy-client' \
    -d 'client_secret=dummy-client-super-secret-xxx' \
    -d "username=${username}" \
    -d "password=${password}" \
    -d 'grant_type=password' \
    -d 'response_type=code' \
    -d 'scope=openid' \
    'http://localhost:8080/realms/dummy/protocol/openid-connect/token' | jq -r '.access_token'
}

access_token=$(get_access_token);

readonly url1="http://localhost:3000/projects.json"

echo requesting ${url1};

curl -H "Authorization: bearer ${access_token}" ${url1};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[]%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulation!&lt;br&gt;
You have setup Keycloak with Rails.&lt;/p&gt;

&lt;p&gt;In the third part of this series, we will setup Authorization for Rails using keycloak.&lt;/p&gt;

&lt;p&gt;You can find the source of this project in the repo:&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>keycloak</category>
      <category>rails</category>
    </item>
    <item>
      <title>Rails and Keycloak, Authentication Authorization, part one</title>
      <dc:creator>Mohammed O. Tillawy</dc:creator>
      <pubDate>Fri, 16 Aug 2024 17:52:48 +0000</pubDate>
      <link>https://forem.com/tillawy/rails-and-keycloak-authentication-authorization-part-one-cd5</link>
      <guid>https://forem.com/tillawy/rails-and-keycloak-authentication-authorization-part-one-cd5</guid>
      <description>&lt;p&gt;First things first, what is Keycloak? and why would you want to use it with Rails?&lt;/p&gt;

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

&lt;p&gt;Keycloak is an open source identity and access management under the &lt;a href="https://www.cncf.io/projects/keycloak/" rel="noopener noreferrer"&gt;CNCF&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What does that mean?&lt;br&gt;
In simple words: Keycloak will find out the identify of your visitors and make sure they are who they claim to be, and maybe grant them proper access to certain resources. &lt;/p&gt;
&lt;h2&gt;
  
  
  What does Keycloak do for me?
&lt;/h2&gt;

&lt;p&gt;It acts as a standalone authentication system for all your application, Rails, Django, Nodes, etc ...&lt;br&gt;
Your application is an &lt;a href="https://openid.net/developers/how-connect-works/" rel="noopener noreferrer"&gt;OpenID&lt;/a&gt; client that trusts Keycloak.&lt;br&gt;
Keycloak helps you can keep all authentication logic out of your application.&lt;br&gt;
For example: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can set Google, Microsoft, Gihtub login in Keycloak, and all your applications will get those for free.&lt;/li&gt;
&lt;li&gt;Web Authentication, user registration, forgot password, etc ...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keycloak is highly configurable. You can change Keycloak's behavior without deployment. &lt;br&gt;
You can configure Keycloak using:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keycloak web interface &lt;/li&gt;
&lt;li&gt;Terraform or opentofu using &lt;a href="https://registry.terraform.io/providers/mrparkers/keycloak/latest/docs" rel="noopener noreferrer"&gt;terraform-provider&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.keycloak.org/docs-api/latest/rest-api/index.html" rel="noopener noreferrer"&gt;REST API &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Third party libraries that use Keycloak REST APIs, for example &lt;a href="https://github.com/looorent/keycloak-admin-ruby" rel="noopener noreferrer"&gt;Keycloak Admin Ruby&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Keycloak is also highly &lt;a href="https://www.keycloak.org/docs/latest/server_development/#_themes" rel="noopener noreferrer"&gt;theme-able&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Shall I use Keycloak with Ruby on Rails?
&lt;/h2&gt;
&lt;h4&gt;
  
  
  Authentication
&lt;/h4&gt;

&lt;p&gt;Authentication means: making sure someone is in fact who he claims to be.&lt;/p&gt;

&lt;p&gt;There are numerous options for authentication for Rails, for example: &lt;/p&gt;

&lt;p&gt;Option 1:&lt;/p&gt;

&lt;p&gt;You can keep things simple, and use Rails built in &lt;a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/SecurePassword/ClassMethods.html" rel="noopener noreferrer"&gt;authenticate_by&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;has_secure_password&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s2"&gt;"jdoe@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="s2"&gt;"abc123"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authenticate_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s2"&gt;"jdoe@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="s2"&gt;"abc123"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Option 2:&lt;/p&gt;

&lt;p&gt;Use &lt;a href="https://github.com/heartcombo/devise" rel="noopener noreferrer"&gt;devise gem&lt;/a&gt;, which is probably the most famous rails authentication system.&lt;/p&gt;

&lt;p&gt;Option 3:&lt;/p&gt;

&lt;p&gt;Use &lt;a href="https://github.com/excid3/revise_auth" rel="noopener noreferrer"&gt;revise gem&lt;/a&gt;, which is very similar to devise gem.&lt;/p&gt;

&lt;p&gt;What ever option your choose, you won't go wrong. &lt;br&gt;
But what if you want your users to login seamlessly using the same credentials to your other applications. &lt;/p&gt;

&lt;p&gt;You can use &lt;a href="https://github.com/doorkeeper-gem/doorkeeper" rel="noopener noreferrer"&gt;doorkeeper gem&lt;/a&gt;. Which can convert your Rails application into an identity provider. But this means that one of your applications will be the single source of truth for users management.   &lt;/p&gt;

&lt;h4&gt;
  
  
  Authorization
&lt;/h4&gt;

&lt;p&gt;Authorization means granting users access to specific resources after being authenticated successfully.&lt;/p&gt;

&lt;p&gt;There are several options, for example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/CanCanCommunity/cancancan" rel="noopener noreferrer"&gt;CanCanCan&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/varvet/pundit" rel="noopener noreferrer"&gt;Pundit&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both are great options, they are baked for Rails. and each has it's own fan base. &lt;/p&gt;

&lt;h5&gt;
  
  
  Can Keycloak totally replace Rails authorization systems?
&lt;/h5&gt;

&lt;p&gt;Nope.&lt;br&gt;
CanCanCan &amp;amp; Pundit have the advantage of database access, they can offer fine grained access to every user.&lt;/p&gt;

&lt;h5&gt;
  
  
  Can Keycloak support Rails authorization systems?
&lt;/h5&gt;

&lt;p&gt;If Keycloak has the users classified into groups, and groups are granted role, Keycloak can offer an extra layer of security for APIs. &lt;/p&gt;

&lt;p&gt;We will setup Keycloak authorization for APIs in part 3 of this series. &lt;/p&gt;

&lt;p&gt;In part two of this series, we will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setup Keycloak using docker and (terraform or opentofu)&lt;/li&gt;
&lt;li&gt;Create a Rails demo application and set it up with Keycloak using omniauth.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In part three of this series, we will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setup Rails with Keycloak for authorization&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>keycloak</category>
      <category>rails</category>
    </item>
  </channel>
</rss>
