<?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: Laith Al Enooz</title>
    <description>The latest articles on DEV Community by Laith Al Enooz (@laithalenooz).</description>
    <link>https://dev.to/laithalenooz</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%2F2291689%2Fea5f5c4b-6765-4bca-8192-eb87580424be.jpeg</url>
      <title>DEV Community: Laith Al Enooz</title>
      <link>https://dev.to/laithalenooz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/laithalenooz"/>
    <language>en</language>
    <item>
      <title>Building a Stateless Multi-Realm Auth Service: Why Your Auth Gateway Doesn't Need a Database</title>
      <dc:creator>Laith Al Enooz</dc:creator>
      <pubDate>Wed, 11 Feb 2026 22:23:34 +0000</pubDate>
      <link>https://dev.to/laithalenooz/building-a-stateless-multi-realm-auth-service-why-your-auth-gateway-doesnt-need-a-database-1bg2</link>
      <guid>https://dev.to/laithalenooz/building-a-stateless-multi-realm-auth-service-why-your-auth-gateway-doesnt-need-a-database-1bg2</guid>
      <description>&lt;h2&gt;
  
  
  The Problem: Why Most Auth Services Are Tightly Coupled
&lt;/h2&gt;

&lt;p&gt;Picture this: you're building a platform that serves multiple applications—a mobile app, a web dashboard, and maybe a partner API. Each needs its own authentication realm in Keycloak, but your auth service is hardcoded to a single realm. To support multiple apps, you'd typically:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Deploy separate auth services for each realm (wasteful)&lt;/li&gt;
&lt;li&gt;Store realm configurations in a database (unnecessary complexity)&lt;/li&gt;
&lt;li&gt;Build an admin UI to manage realm mappings (even more code to maintain)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What if I told you there's a better way? One that requires &lt;strong&gt;zero database&lt;/strong&gt;, &lt;strong&gt;zero configuration management&lt;/strong&gt;, and scales horizontally without any server-side state?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Insight: Realm and Client as Request Parameters
&lt;/h2&gt;

&lt;p&gt;Think of your auth service like a translator at the UN. The translator doesn't need to remember which language each delegate speaks—they tell you in real-time. Similarly, your auth service doesn't need to store which realm each application uses; the application tells you with every request.&lt;/p&gt;

&lt;p&gt;This is the core insight behind the &lt;strong&gt;stateless multi-realm architecture&lt;/strong&gt;: treat realm and client credentials as &lt;strong&gt;request-scoped parameters&lt;/strong&gt;, not server configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Traditional approach: hardcoded configuration&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;keycloakURL&lt;/span&gt;   &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;realm&lt;/span&gt;         &lt;span class="kt"&gt;string&lt;/span&gt;  &lt;span class="c"&gt;// ❌ Server-wide configuration&lt;/span&gt;
    &lt;span class="n"&gt;clientID&lt;/span&gt;      &lt;span class="kt"&gt;string&lt;/span&gt;  &lt;span class="c"&gt;// ❌ Fixed at startup&lt;/span&gt;
    &lt;span class="n"&gt;clientSecret&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;  &lt;span class="c"&gt;// ❌ All apps share same client&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Stateless approach: per-request parameters&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;LoginRequest&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;RealmName&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`header:"X-Realm-Name"`&lt;/span&gt;     &lt;span class="c"&gt;// ✅ Dynamic per request&lt;/span&gt;
    &lt;span class="n"&gt;ClientID&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`header:"X-Client-Id"`&lt;/span&gt;      &lt;span class="c"&gt;// ✅ App specifies its client&lt;/span&gt;
    &lt;span class="n"&gt;ClientSecret&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`header:"X-Client-Secret"`&lt;/span&gt;  &lt;span class="c"&gt;// ✅ No shared secrets&lt;/span&gt;
    &lt;span class="n"&gt;Username&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"username"`&lt;/span&gt;
    &lt;span class="n"&gt;Password&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"password"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Domain Modeling: Making Realm a First-Class Citizen
&lt;/h2&gt;

&lt;p&gt;The shift from server configuration to request parameters is more than a technical detail—it's a &lt;strong&gt;domain modeling decision&lt;/strong&gt; that fundamentally changes how your service operates.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Gateway Pattern
&lt;/h3&gt;

&lt;p&gt;Instead of maintaining user state or realm mappings, the service becomes a &lt;strong&gt;pure gateway&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────┐
│   Mobile    │─┐
│     App     │ │  X-Realm-Name: mobile-realm
└─────────────┘ │  X-Client-Id: mobile-app
                │
┌─────────────┐ │  ┌──────────────────┐      ┌──────────────┐
│     Web     │─┼─→│  Auth Service    │─────→│  Keycloak    │
│  Dashboard  │ │  │  (Stateless)     │←─────│ (Source of   │
└─────────────┘ │  └──────────────────┘      │   Truth)     │
                │       ↕ Redis                └──────────────┘
┌─────────────┐ │    (Caching Only)
│  Partner    │─┘
│     API     │    X-Realm-Name: partner-realm
└─────────────┘    X-Client-Id: partner-client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what's &lt;strong&gt;not&lt;/strong&gt; in this diagram: there's no database, no admin interface, no configuration service. The auth service is genuinely stateless—it can be scaled up or down instantly without any coordination.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Usage: How It Works
&lt;/h2&gt;

&lt;p&gt;Let's see how different applications use the same service instance:&lt;/p&gt;

&lt;h3&gt;
  
  
  Mobile App Login
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://auth.example.com/api/v1/auth/login &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Realm-Name: mobile-realm"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Client-Id: mobile-app"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Client-Secret: mobile-secret-xyz"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&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;'{
    "username": "user@example.com",
    "password": "secure-password"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Web Dashboard Login (Same Service!)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://auth.example.com/api/v1/auth/login &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Realm-Name: company-realm"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Client-Id: web-dashboard"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Client-Secret: web-secret-abc"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&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;'{
    "username": "admin@company.com",
    "password": "admin-password"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same endpoint, same service instance, different realms—&lt;strong&gt;no configuration needed&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Deep Dive
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The Stateless Keycloak Client
&lt;/h3&gt;

&lt;p&gt;The heart of the service is a Keycloak client that builds request contexts dynamically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;KeycloakClient&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;baseURL&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;httpClient&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;       &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cache&lt;/span&gt;
    &lt;span class="c"&gt;// Note: NO realm, NO clientID stored here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kc&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;KeycloakClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="n"&gt;LoginRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;TokenResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Build realm-specific URL from request parameters&lt;/span&gt;
    &lt;span class="n"&gt;tokenURL&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s/realms/%s/protocol/openid-connect/token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RealmName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Use client credentials from request (not from config)&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Values&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"client_id"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClientID&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="s"&gt;"client_secret"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClientSecret&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Username&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="s"&gt;"grant_type"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Execute request with tracing context&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;makeRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokenURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&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;
  
  
  2. Intelligent Caching Strategy
&lt;/h3&gt;

&lt;p&gt;Even though the service is stateless, we still use Redis for &lt;strong&gt;performance&lt;/strong&gt;, not for state management:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Cache key includes realm context&lt;/span&gt;
&lt;span class="n"&gt;cacheKey&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"token:%s:%s:%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RealmName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClientID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// Check cache first&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cachedToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cachedToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Cache miss: fetch from Keycloak&lt;/span&gt;
&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetchFromKeycloak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Cache with TTL slightly less than token expiry&lt;/span&gt;
&lt;span class="n"&gt;ttl&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExpiresIn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;
&lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Important distinction&lt;/strong&gt;: The cache is an optimization, not a requirement. If Redis goes down, the service continues to function—it just makes more calls to Keycloak.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Observability: Realm-Aware Tracing
&lt;/h3&gt;

&lt;p&gt;OpenTelemetry tracing automatically includes realm context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kc&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;KeycloakClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;makeRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tracer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"keycloak.request"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithAttributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"realm.name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"realm_name"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"client.id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"client_id"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"operation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"token"&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;defer&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;End&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Make HTTP request with propagated context&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c"&gt;// Record metrics by realm&lt;/span&gt;
    &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RecordRequestDuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Since&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s"&gt;"realm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"realm_name"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s"&gt;"client"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"client_id"&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="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you &lt;strong&gt;distributed tracing across realm boundaries&lt;/strong&gt; in tools like Jaeger:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP POST /api/v1/auth/login [realm=mobile-realm, client=mobile-app] (120ms)
  ├─ Cache.Get [key=token:mobile-realm:mobile-app:user] (2ms) MISS
  ├─ Keycloak.GetToken [realm=mobile-realm] (95ms)
  └─ Cache.Set [ttl=3570s] (3ms)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Production Readiness: The Complete Package
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dual Interface: gRPC + REST
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Same business logic, two interfaces&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;keycloakClient&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;keycloak&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;          &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cache&lt;/span&gt;
    &lt;span class="n"&gt;metrics&lt;/span&gt;        &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Collector&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// gRPC endpoint&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoginRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoginResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&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="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keycloakClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;toLoginRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// HTTP endpoint (Gin handler)&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;HandleLogin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="n"&gt;LoginRequest&lt;/span&gt;

    &lt;span class="c"&gt;// Extract realm/client from headers&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RealmName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"X-Realm-Name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClientID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"X-Client-Id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClientSecret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"X-Client-Secret"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ShouldBindJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"invalid request"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keycloakClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&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;Context&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;401&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"authentication failed"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&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;
  
  
  Health Checks with Dependency Monitoring
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;HealthChecker&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;keycloakClient&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;keycloak&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;          &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cache&lt;/span&gt;
    &lt;span class="n"&gt;lastCheck&lt;/span&gt;      &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt;
    &lt;span class="n"&gt;cachedStatus&lt;/span&gt;   &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HealthStatus&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;             &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RWMutex&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HealthChecker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HealthStatus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;HealthStatus&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Dependencies&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;DependencyStatus&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Check Keycloak (source of truth)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keycloakClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HealthCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dependencies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"keycloak"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DependencyStatus&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"unhealthy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"degraded"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dependencies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"keycloak"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DependencyStatus&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"healthy"&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="c"&gt;// Check Redis (optional dependency)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dependencies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"redis"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DependencyStatus&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"unhealthy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"cache unavailable (service will continue without caching)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c"&gt;// Note: Service remains healthy even if cache is down&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dependencies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"redis"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DependencyStatus&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"healthy"&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;return&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Graceful Shutdown
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Setup servers&lt;/span&gt;
    &lt;span class="n"&gt;httpServer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;setupHTTPServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;grpcServer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;setupGRPCServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Graceful shutdown handling&lt;/span&gt;
    &lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Interrupt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIGTERM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrServerClosed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HTTP server error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;grpcServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gRPC server error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Shutting down gracefully..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Give in-flight requests time to complete&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;httpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Shutdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;grpcServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GracefulStop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Servers stopped"&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;
  
  
  Performance Characteristics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Horizontal Scalability
&lt;/h3&gt;

&lt;p&gt;Because the service is truly stateless:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Load Balancer
     ↓
┌────┴────┐
│  Pod 1  │  ← Can scale from 1 to 100 pods instantly
├─────────┤
│  Pod 2  │  ← No coordination needed between pods
├─────────┤
│  Pod 3  │  ← No sticky sessions required
└─────────┘
     ↓
  Keycloak
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Caching Strategy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request Flow with Cache:

1. Request arrives → Check cache (2ms)
   ├─ Hit (90% of requests) → Return cached token (total: 2ms)
   └─ Miss (10% of requests) → Fetch from Keycloak (100ms) → Cache (3ms) (total: 103ms)

Result: Average response time = (0.9 × 2ms) + (0.1 × 103ms) = 12.1ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Load Testing Results
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1000 concurrent users, 10,000 requests&lt;/span&gt;
wrk &lt;span class="nt"&gt;-t12&lt;/span&gt; &lt;span class="nt"&gt;-c1000&lt;/span&gt; &lt;span class="nt"&gt;-d30s&lt;/span&gt; &lt;span class="nt"&gt;--latency&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Realm-Name: test-realm"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Client-Id: test-client"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Client-Secret: secret"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  http://localhost:8080/api/v1/auth/login

&lt;span class="c"&gt;# Results:&lt;/span&gt;
Latency Distribution
  50%    11ms
  75%    15ms
  90%    22ms
  99%    45ms

Requests/sec: 8,234
Transfer/sec: 2.1MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When to Use This Pattern
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ Perfect For:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-tenant platforms&lt;/strong&gt; where each tenant has its own Keycloak realm&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microservices architectures&lt;/strong&gt; where services need to scale independently&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud-native deployments&lt;/strong&gt; where you want instant scalability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost-sensitive environments&lt;/strong&gt; where reducing infrastructure is important&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-availability requirements&lt;/strong&gt; where eliminating single points of failure matters&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ❌ Not Ideal For:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single-realm applications&lt;/strong&gt; (though it still works, you're adding complexity without benefit)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Services that need complex user data beyond what Keycloak provides&lt;/strong&gt; (at that point, you probably need a user service)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scenarios with extremely high request rates where even Redis latency is too much&lt;/strong&gt; (consider in-memory caching with careful cache coherency strategies)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Trade-offs: What You're Really Giving Up
&lt;/h2&gt;

&lt;p&gt;Let's be honest about the constraints:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Client Secret in Headers
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Trade-off&lt;/strong&gt;: Client secrets in request headers means more data on the wire.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use TLS everywhere (you should anyway)&lt;/li&gt;
&lt;li&gt;Client secrets aren't user passwords—they're app credentials&lt;/li&gt;
&lt;li&gt;Consider header compression in your load balancer&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. No Custom User Metadata
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Trade-off&lt;/strong&gt;: You can't easily store custom user metadata beyond what Keycloak supports.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Keycloak's user attributes (they're quite flexible)&lt;/li&gt;
&lt;li&gt;If you need complex user profiles, build a separate user service&lt;/li&gt;
&lt;li&gt;This service focuses on &lt;strong&gt;authentication&lt;/strong&gt;, not user management&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Trust in Keycloak
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Trade-off&lt;/strong&gt;: Keycloak becomes a critical dependency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploy Keycloak in HA mode (you should anyway)&lt;/li&gt;
&lt;li&gt;The service continues to work with cached tokens even if Keycloak has brief outages&lt;/li&gt;
&lt;li&gt;Monitor Keycloak health and set up proper alerting&lt;/li&gt;
&lt;/ul&gt;

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

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Required&lt;/span&gt;
- Go 1.25+
- Redis &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for &lt;/span&gt;caching&lt;span class="o"&gt;)&lt;/span&gt;
- Keycloak server

&lt;span class="c"&gt;# Optional (for observability)&lt;/span&gt;
- Jaeger or any OTLP-compatible collector
- Prometheus
- Grafana
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Quick Start
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone the repo&lt;/span&gt;
git clone https://github.com/laithalenooz/auth-service-go
&lt;span class="nb"&gt;cd &lt;/span&gt;auth-service-go

&lt;span class="c"&gt;# Set up environment&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
&lt;span class="c"&gt;# Edit .env with your Keycloak details&lt;/span&gt;

&lt;span class="c"&gt;# Start with Docker Compose (includes Redis, Keycloak, Jaeger, Prometheus, Grafana)&lt;/span&gt;
docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;

&lt;span class="c"&gt;# Run the service&lt;/span&gt;
make run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Your First Request
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a user in Keycloak's master realm&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8080/api/v1/auth/register &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Realm-Name: master"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Client-Id: auth-service"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Client-Secret: your-client-secret"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&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;'{
    "username": "testuser",
    "email": "test@example.com",
    "password": "password123",
    "first_name": "Test",
    "last_name": "User"
  }'&lt;/span&gt;

&lt;span class="c"&gt;# Login&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8080/api/v1/auth/login &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Realm-Name: master"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Client-Id: auth-service"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Client-Secret: your-client-secret"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&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;'{
    "username": "testuser",
    "password": "password123"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Observability in Action
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Jaeger Traces
&lt;/h3&gt;

&lt;p&gt;Visit &lt;code&gt;http://localhost:16686&lt;/code&gt; to see distributed traces:&lt;/p&gt;

&lt;p&gt;Each trace shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which realm was accessed&lt;/li&gt;
&lt;li&gt;Which client made the request&lt;/li&gt;
&lt;li&gt;Cache hit/miss&lt;/li&gt;
&lt;li&gt;Keycloak response time&lt;/li&gt;
&lt;li&gt;Total request duration&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Prometheus Metrics
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Authentication success rate by realm
sum(rate(auth_login_success_total[5m])) by (realm_name, client_id)

# Cache hit rate
sum(rate(cache_hits_total[5m])) / sum(rate(cache_requests_total[5m]))

# Request latency by realm (p95)
histogram_quantile(0.95, 
  sum(rate(http_request_duration_seconds_bucket[5m])) by (realm_name, le)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Grafana Dashboards
&lt;/h3&gt;

&lt;p&gt;The project includes pre-built dashboards showing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request rate and latency by realm&lt;/li&gt;
&lt;li&gt;Authentication success/failure rates&lt;/li&gt;
&lt;li&gt;Cache performance&lt;/li&gt;
&lt;li&gt;Service health status&lt;/li&gt;
&lt;li&gt;Keycloak response times&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I Learned Building This
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Statelessness is Liberating
&lt;/h3&gt;

&lt;p&gt;Once you stop trying to maintain state, a lot of complexity disappears. No database migrations, no cache coherency issues, no distributed locks. The service becomes a pure function: requests go in, responses come out.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Domain Modeling Matters More Than Technology
&lt;/h3&gt;

&lt;p&gt;The decision to treat realm and client as request parameters wasn't primarily a technical decision—it was a &lt;strong&gt;domain modeling insight&lt;/strong&gt;. Understanding that "realm context" belongs to the request, not the server, simplified everything else.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Observability Isn't Optional
&lt;/h3&gt;

&lt;p&gt;In a stateless system where each request might hit a different realm, comprehensive tracing is the only way to debug issues. OpenTelemetry tracing paid for itself within the first week.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Caching for Performance, Not Correctness
&lt;/h3&gt;

&lt;p&gt;Using Redis as a pure performance optimization (not a source of truth) means you can reason about the system with or without cache. This makes testing easier and reduces the blast radius when something goes wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Rethinking Authentication Layers
&lt;/h2&gt;

&lt;p&gt;Most authentication services are designed around the assumption that they need to "know" about their users and clients. By inverting this—making the &lt;strong&gt;caller&lt;/strong&gt; provide the context—we eliminate entire classes of complexity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No configuration management&lt;/li&gt;
&lt;li&gt;No database to maintain&lt;/li&gt;
&lt;li&gt;No synchronization between instances&lt;/li&gt;
&lt;li&gt;No limits on horizontal scaling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is a service that does one thing well: &lt;strong&gt;intelligently proxy authentication requests to Keycloak&lt;/strong&gt;, with caching and observability included.&lt;/p&gt;

&lt;p&gt;If you're building a multi-tenant platform or a microservices architecture, consider whether your authentication layer actually needs to store anything. You might be able to delete more code than you write.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/laithalenooz/auth-service-go" rel="noopener noreferrer"&gt;laithalenooz/auth-service-go&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tech Stack&lt;/strong&gt;: Go, gRPC, Gin, Redis, Keycloak, OpenTelemetry, Prometheus&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Found this useful?&lt;/strong&gt; Star the repo and let me know what you think in the comments!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Questions? I'm happy to discuss the architecture, trade-offs, or help with implementation details.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>architecture</category>
      <category>authentication</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Resolving Audio Issues on Arch Linux with Hyprland: A Step-by-Step Guide</title>
      <dc:creator>Laith Al Enooz</dc:creator>
      <pubDate>Sat, 21 Dec 2024 09:15:55 +0000</pubDate>
      <link>https://dev.to/laithalenooz/resolving-audio-issues-on-arch-linux-with-hyprland-a-step-by-step-guide-2n</link>
      <guid>https://dev.to/laithalenooz/resolving-audio-issues-on-arch-linux-with-hyprland-a-step-by-step-guide-2n</guid>
      <description>&lt;p&gt;Arch Linux users who have embraced the Hyprland compositor for a sleek and modern desktop experience might occasionally encounter audio-related challenges. These issues can stem from conflicts between audio servers or misconfigurations within the system. Fortunately, resolving these problems is straightforward. This article outlines a simple two-step process to address common audio issues by transitioning from PulseAudio to PipeWire, a more modern and versatile audio server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding the Issue
&lt;/h3&gt;

&lt;p&gt;Hyprland, known for its dynamic tiling and Wayland support, relies on a smooth audio experience to complement its visual prowess. However, some users have reported audio disruptions, such as no sound output or intermittent audio playback. These problems are often linked to PulseAudio, the traditional sound server, which might conflict with newer components or the system's configuration under Hyprland.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution: Transitioning to PipeWire
&lt;/h3&gt;

&lt;p&gt;PipeWire has emerged as a robust alternative to PulseAudio, offering improved performance and better integration with modern desktop environments. Transitioning to PipeWire can resolve audio issues by replacing PulseAudio with a more compatible and efficient audio server.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Remove PulseAudio
&lt;/h4&gt;

&lt;p&gt;Begin by attempting to remove PulseAudio from your system. Open a terminal and execute the following command:&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;sudo &lt;/span&gt;pacman &lt;span class="nt"&gt;-Rns&lt;/span&gt; pulseaudio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Explanation:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sudo&lt;/code&gt;: Runs the command with administrative privileges.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pacman&lt;/code&gt;: The package manager for Arch Linux.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-Rns&lt;/code&gt;: Removes the specified package (&lt;code&gt;pulseaudio&lt;/code&gt;) along with its dependencies (&lt;code&gt;-s&lt;/code&gt;) and any configuration files (&lt;code&gt;-n&lt;/code&gt;) that are not required by other packages.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If the removal process fails and indicates that no packages can be removed, it's best to proceed without attempting to uninstall PulseAudio. This means that PulseAudio is either not installed or is required by other essential packages on your system.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Install PipeWire and Related Packages
&lt;/h4&gt;

&lt;p&gt;Next, install PipeWire along with its complementary components to ensure full audio functionality. Execute the following command:&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;sudo &lt;/span&gt;pacman &lt;span class="nt"&gt;-S&lt;/span&gt; pipewire wireplumber pipewire-pulse pipewire-alsa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Explanation:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-S&lt;/code&gt;: Synchronizes packages, installing or updating them as needed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pipewire&lt;/code&gt;: The core PipeWire package.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;wireplumber&lt;/code&gt;: A session manager for PipeWire, handling the configuration and policy.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pipewire-pulse&lt;/code&gt;: Provides PulseAudio compatibility, allowing applications that rely on PulseAudio to function seamlessly with PipeWire.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pipewire-alsa&lt;/code&gt;: Ensures compatibility with ALSA (Advanced Linux Sound Architecture), which many low-level audio applications depend on.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;During the installation, Pacman may prompt you to remove conflicting packages. If this occurs, respond affirmatively by typing &lt;code&gt;y&lt;/code&gt; (yes) to allow Pacman to resolve these conflicts automatically.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Restart Your System
&lt;/h4&gt;

&lt;p&gt;After successfully installing PipeWire and its associated packages, it's crucial to restart your system to apply the changes. This ensures that PipeWire replaces PulseAudio as the active audio server and that all services initialize correctly.&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;sudo &lt;/span&gt;reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Transitioning from PulseAudio to PipeWire can significantly enhance your audio experience on Arch Linux with Hyprland. PipeWire's modern architecture not only resolves common audio issues but also offers better performance and flexibility for future audio management needs. By following the simple steps outlined above, you can swiftly address audio disruptions and enjoy a seamless multimedia experience on your Hyprland-powered system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Additional Tips:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Verify PipeWire is Running:&lt;/strong&gt;
After rebooting, you can check if PipeWire is active by running:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  systemctl &lt;span class="nt"&gt;--user&lt;/span&gt; status pipewire
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command should display that PipeWire is active and running.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configure PipeWire:&lt;/strong&gt;&lt;br&gt;
PipeWire is highly configurable. You can adjust its settings by editing configuration files located in &lt;code&gt;/etc/pipewire/&lt;/code&gt; or &lt;code&gt;~/.config/pipewire/&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stay Updated:&lt;/strong&gt;&lt;br&gt;
Regularly update your system to benefit from the latest PipeWire improvements and bug fixes:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nb"&gt;sudo &lt;/span&gt;pacman &lt;span class="nt"&gt;-Syu&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By proactively managing your audio server and leveraging PipeWire's capabilities, you ensure a stable and high-quality audio environment tailored to your Arch Linux and Hyprland setup.&lt;/p&gt;

</description>
      <category>archlinux</category>
      <category>hyprland</category>
      <category>linux</category>
    </item>
    <item>
      <title>The Power of a Personal Wiki: Boosting Productivity for Developers</title>
      <dc:creator>Laith Al Enooz</dc:creator>
      <pubDate>Mon, 28 Oct 2024 08:20:11 +0000</pubDate>
      <link>https://dev.to/laithalenooz/the-power-of-a-personal-wiki-boosting-productivity-for-developers-14a3</link>
      <guid>https://dev.to/laithalenooz/the-power-of-a-personal-wiki-boosting-productivity-for-developers-14a3</guid>
      <description>&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%2Fplascijedqqydq31bdmr.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%2Fplascijedqqydq31bdmr.png" alt="Image description" width="800" height="730"&gt;&lt;/a&gt;In the fast-paced world of software development, effectively managing and organizing knowledge is crucial. One tool that can significantly enhance your workflow is maintaining a &lt;strong&gt;personal wiki&lt;/strong&gt;. In this article, we'll delve into the benefits of having your own wiki and how it can elevate your development process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Create a Personal Wiki?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Centralized Knowledge Repository
&lt;/h3&gt;

&lt;p&gt;Developers often accumulate a vast amount of information—code snippets, configurations, troubleshooting steps, and best practices. A personal wiki serves as a centralized hub where all this knowledge is organized and easily accessible.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Enhanced Productivity
&lt;/h3&gt;

&lt;p&gt;Having immediate access to your curated information saves time that would otherwise be spent searching through documentation or past projects. This efficiency allows you to focus more on solving complex problems rather than reinventing the wheel.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Personalized Learning
&lt;/h3&gt;

&lt;p&gt;Documenting your learnings reinforces understanding. A personal wiki provides a platform to record new technologies, frameworks, or methodologies you encounter, tailored to your comprehension and future reference.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Optional Collaboration
&lt;/h3&gt;

&lt;p&gt;While a personal wiki is primarily for individual use, you can choose to share it with team members. This fosters knowledge sharing and ensures everyone is on the same page, especially when working on collaborative projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Your Personal Wiki
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Choosing the Right Platform
&lt;/h3&gt;

&lt;p&gt;There are several platforms you can use to set up your wiki:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MediaWiki&lt;/strong&gt;: The engine behind Wikipedia; powerful but may be more than needed for personal use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dokuwiki&lt;/strong&gt;: Simple, lightweight, and doesn't require a database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notion or Obsidian&lt;/strong&gt;: Modern tools that combine note-taking with wiki features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git-based Wikis&lt;/strong&gt;: Use platforms like GitHub or GitLab to create a wiki that integrates with version control.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Installation and Configuration
&lt;/h3&gt;

&lt;p&gt;For simplicity, let's consider using &lt;strong&gt;Dokuwiki&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Download Dokuwiki&lt;/strong&gt; from the &lt;a href="https://www.dokuwiki.org/download" rel="noopener noreferrer"&gt;official website&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extract and Upload&lt;/strong&gt; the files to your web server or local environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run the Installer&lt;/strong&gt; by accessing the installation script through your browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure Settings&lt;/strong&gt;: Set up your admin account and customize your wiki's appearance and permissions.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Organizing Your Wiki
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Namespaces&lt;/strong&gt;: Categorize content into namespaces like &lt;code&gt;Languages&lt;/code&gt;, &lt;code&gt;Tools&lt;/code&gt;, &lt;code&gt;Projects&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pages and Subpages&lt;/strong&gt;: Create detailed pages for specific topics (e.g., &lt;code&gt;Kafka/Setup&lt;/code&gt;, &lt;code&gt;AWS/SQS&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Templates and Plugins&lt;/strong&gt;: Enhance functionality and aesthetics with community-contributed extensions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Maximizing the Benefits
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Regular Updates
&lt;/h3&gt;

&lt;p&gt;Consistently update your wiki with new findings, resolved issues, and updated best practices to keep it relevant.&lt;/p&gt;

&lt;h3&gt;
  
  
  Search Functionality
&lt;/h3&gt;

&lt;p&gt;Utilize the search features to quickly locate information, making your wiki a powerful quick-reference tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integration with Other Tools
&lt;/h3&gt;

&lt;p&gt;Some wikis allow integration with IDEs or editors, enabling you to document directly from your development environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a Personal Wiki Enhances Your Work
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Streamlined Onboarding
&lt;/h3&gt;

&lt;p&gt;If you decide to share parts of your wiki with new team members, it can significantly reduce onboarding time by providing them with a wealth of information at their fingertips.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem-Solving Efficiency
&lt;/h3&gt;

&lt;p&gt;Quickly recalling how you solved a past issue can save hours of troubleshooting. Documenting these experiences creates a valuable troubleshooting guide.&lt;/p&gt;

&lt;h3&gt;
  
  
  Knowledge Retention
&lt;/h3&gt;

&lt;p&gt;Writing down what you've learned ensures that critical information isn't lost over time, especially for infrequent but important tasks.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start Small&lt;/strong&gt;: Begin with essential topics and gradually expand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintain Consistency&lt;/strong&gt;: Use a consistent structure for ease of navigation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backup Regularly&lt;/strong&gt;: Protect your data by keeping backups of your wiki content.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;A personal wiki is more than just a collection of notes—it's a personalized knowledge base that grows with you throughout your career. It enhances productivity, supports continuous learning, and becomes an indispensable tool in your development arsenal.&lt;/p&gt;




</description>
      <category>wiki</category>
      <category>development</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Getting Started with Apache Kafka: A Backend Engineer's Perspective</title>
      <dc:creator>Laith Al Enooz</dc:creator>
      <pubDate>Mon, 28 Oct 2024 08:17:18 +0000</pubDate>
      <link>https://dev.to/laithalenooz/getting-started-with-apache-kafka-a-backend-engineers-perspective-1ci</link>
      <guid>https://dev.to/laithalenooz/getting-started-with-apache-kafka-a-backend-engineers-perspective-1ci</guid>
      <description>&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%2Flakgec7f592n5ertx5cn.jpg" 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%2Flakgec7f592n5ertx5cn.jpg" alt="Image description" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a backend software engineer with over 7 years of experience, I've had the opportunity to work with various technologies to build scalable and efficient systems. One tool that has consistently proven its worth in handling real-time data streams is &lt;strong&gt;Apache Kafka&lt;/strong&gt;. In this article, I'll provide an introduction to Kafka and share insights on how it can be leveraged in backend development.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Apache Kafka?
&lt;/h2&gt;

&lt;p&gt;Apache Kafka is an open-source distributed event streaming platform used by thousands of companies for high-performance data pipelines, streaming analytics, data integration, and mission-critical applications. It excels at managing real-time data feeds and is designed to handle data streams from multiple sources and deliver them to multiple consumers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Kafka?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Kafka's distributed architecture allows it to scale horizontally by adding more brokers to the cluster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fault Tolerance&lt;/strong&gt;: Data is replicated across multiple brokers, ensuring no single point of failure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Capable of handling thousands of messages per second with minimal latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Durability&lt;/strong&gt;: Messages are stored on disk, providing durability and reliability.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Core Concepts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Topics&lt;/strong&gt;: Categories or feed names to which messages are published.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Producers&lt;/strong&gt;: Applications that publish messages to Kafka topics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consumers&lt;/strong&gt;: Applications that subscribe to topics and process the messages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Brokers&lt;/strong&gt;: Kafka servers that manage the persistence and replication of messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting Up Kafka
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Java 8+&lt;/strong&gt;: Kafka runs on the JVM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zookeeper&lt;/strong&gt;: Manages the Kafka cluster (Note: As of Kafka 2.8, Zookeeper can be optional).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Installation Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Download Kafka&lt;/strong&gt; from the &lt;a href="https://kafka.apache.org/downloads" rel="noopener noreferrer"&gt;official website&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extract&lt;/strong&gt; the files to your desired directory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start Zookeeper&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   bin/zookeeper-server-start.sh config/zookeeper.properties
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start Kafka Broker&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   bin/kafka-server-start.sh config/server.properties
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Basic Operations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating a Topic
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bin/kafka-topics.sh &lt;span class="nt"&gt;--create&lt;/span&gt; &lt;span class="nt"&gt;--topic&lt;/span&gt; my-first-topic &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9092 &lt;span class="nt"&gt;--replication-factor&lt;/span&gt; 1 &lt;span class="nt"&gt;--partitions&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Producing Messages
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bin/kafka-console-producer.sh &lt;span class="nt"&gt;--topic&lt;/span&gt; my-first-topic &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9092
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Type your messages and hit enter to send.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consuming Messages
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bin/kafka-console-consumer.sh &lt;span class="nt"&gt;--topic&lt;/span&gt; my-first-topic &lt;span class="nt"&gt;--from-beginning&lt;/span&gt; &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9092
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see the messages you produced displayed here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating Kafka with Backend Applications
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Using Kafka with Python (Kafka-Python)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;kafka&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;KafkaProducer&lt;/span&gt;

&lt;span class="n"&gt;producer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KafkaProducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bootstrap_servers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;localhost:9092&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-first-topic&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello, Kafka!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using Kafka with Node.js (Kafka-node)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;kafka&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kafka-node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Producer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;kafka&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Producer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;kafka&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;KafkaClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;kafkaHost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localhost:9092&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;producer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Producer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ready&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt; &lt;span class="na"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-first-topic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, Kafka!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;
  
  
  Using Kafka with PHP (php-kafka)
&lt;/h3&gt;

&lt;p&gt;Since PHP doesn't have official Kafka support, you can use extensions like &lt;code&gt;php-rdkafka&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Use Cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Microservices Communication&lt;/strong&gt;: Decouple services by using Kafka as an event bus.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Activity Tracking&lt;/strong&gt;: Collect user activities and logs for real-time monitoring.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Messaging Systems&lt;/strong&gt;: Build robust messaging systems that require high throughput.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use Multiple Partitions&lt;/strong&gt;: Increase throughput by allowing parallel consumption.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor Consumer Lag&lt;/strong&gt;: Keep an eye on consumer lag to ensure consumers are keeping up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure Your Cluster&lt;/strong&gt;: Implement SSL encryption and authentication mechanisms.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Apache Kafka is a powerful tool for building scalable and real-time data pipelines. Its ability to handle high volumes of data with low latency makes it a valuable asset in any backend engineer's toolkit. Whether you're working with PHP, Python, or Node.js, integrating Kafka can significantly enhance your system's performance and reliability.&lt;/p&gt;




</description>
      <category>kafka</category>
      <category>pubsub</category>
      <category>backend</category>
      <category>pipelines</category>
    </item>
  </channel>
</rss>
