<?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: CHRISTIAN OTIENO</title>
    <description>The latest articles on DEV Community by CHRISTIAN OTIENO (@christian-otieno).</description>
    <link>https://dev.to/christian-otieno</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3965933%2F720b1bcb-1e3a-4858-9f15-297806a00557.jpg</url>
      <title>DEV Community: CHRISTIAN OTIENO</title>
      <link>https://dev.to/christian-otieno</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/christian-otieno"/>
    <language>en</language>
    <item>
      <title>Demystifying JWTs: What Actually Happens Under the Hood published: true tags: webdev, security, javascript, architecture</title>
      <dc:creator>CHRISTIAN OTIENO</dc:creator>
      <pubDate>Mon, 14 Sep 2026 16:11:44 +0000</pubDate>
      <link>https://dev.to/christian-otieno/demystifying-jwts-what-actually-happens-under-the-hood-published-true-tags-webdev-security-1id</link>
      <guid>https://dev.to/christian-otieno/demystifying-jwts-what-actually-happens-under-the-hood-published-true-tags-webdev-security-1id</guid>
      <description>&lt;p&gt;JSON Web Tokens (JWTs) are practically everywhere. We reach for them when building microservices, mobile APIs, and single-page apps.&lt;/p&gt;

&lt;p&gt;Yet when asked how they actually work under the hood, the standard developer answer usually defaults to:&lt;/p&gt;

&lt;p&gt;"It's a signed string you store in localStorage and pass along in an Authorization header."&lt;/p&gt;

&lt;p&gt;Let’s dismantle that abstraction. A JWT is not encrypted by default, it is rarely magic, and implementing it blindly introduces real security headaches.&lt;/p&gt;

&lt;p&gt;Here is what is actually going on under the hood.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Anatomy of a JWT&lt;/strong&gt;&lt;br&gt;
A JWT is fundamentally a single string divided into three distinct segments separated by dots (.):&lt;/p&gt;

&lt;p&gt;_&lt;/p&gt;

&lt;h3&gt;
  
  
  Plaintext
&lt;/h3&gt;

&lt;p&gt;header.payload.signature&lt;br&gt;
_&lt;br&gt;
Every segment is encoded using Base64Url—not encrypted. Anyone who intercepts the token can paste it into an online decoder and inspect the data instantly.&lt;/p&gt;

&lt;p&gt;Let’s break down the three parts.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Header
The header contains metadata about the token: the type and the cryptographic algorithm used to secure it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;JSON&lt;br&gt;
{&lt;br&gt;
  "alg": "HS256",&lt;br&gt;
  "typ": "JWT"&lt;br&gt;
}&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;alg: The signing algorithm (e.g., symmetric algorithms like HS256, or asymmetric key pairs like RS256).&lt;/li&gt;
&lt;li&gt;&lt;p&gt;typ: Almost universally set to "JWT".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Payload&lt;br&gt;
The payload contains the claims—statements about the user and context the server needs to function statelessly.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;JSON&lt;br&gt;
{&lt;br&gt;
  "sub": "usr_94810284",&lt;br&gt;
  "name": "Jane Doe",&lt;br&gt;
  "role": "admin",&lt;br&gt;
  "iat": 1711926000,&lt;br&gt;
  "exp": 1711929600&lt;br&gt;
}&lt;br&gt;
Claims fall into two primary buckets:&lt;/p&gt;

&lt;p&gt;Registered claims: Standardized keys like sub (subject/user ID), iat (issued-at timestamp), and exp (expiration timestamp).&lt;/p&gt;

&lt;p&gt;Custom claims: Application-specific context like role, tenant_id, or access scopes.&lt;/p&gt;

&lt;p&gt;⚠️ Critical Security Rule: Never store sensitive data (passwords, private API keys, or unencrypted PII) inside a JWT payload. Encoding is not encryption.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Signature
This is the integrity anchor of the entire token. The signature prevents tampering.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To generate it, the issuing server takes the Base64Url-encoded header, appends the Base64Url-encoded payload, and hashes them using a private secret:&lt;/p&gt;

&lt;p&gt;JavaScript&lt;br&gt;
const signature = HMACSHA256(&lt;br&gt;
  &lt;code&gt;${base64UrlEncode(header)}.${base64UrlEncode(payload)}&lt;/code&gt;,&lt;br&gt;
  SERVER_SECRET_KEY&lt;br&gt;
);&lt;br&gt;
When a client sends the token back, the server re-runs that exact calculation. If the newly calculated signature matches the signature attached to the token, two things are guaranteed:&lt;/p&gt;

&lt;p&gt;Integrity: The header and payload were not altered in transit.&lt;/p&gt;

&lt;p&gt;Authenticity: The token was issued by an entity holding the secret key.&lt;/p&gt;

&lt;p&gt;The Lifecycle of a Stateless Request&lt;br&gt;
Here is the complete authentication flow in practice:&lt;/p&gt;

&lt;p&gt;[ Client ]                                          [ Server ]&lt;br&gt;
    |                                                    |&lt;br&gt;
    |---- 1. POST /api/login (Credentials) -------------&amp;gt;|&lt;br&gt;
    |                                                    |-- Validates credentials&lt;br&gt;
    |                                                    |-- Signs JWT with secret&lt;br&gt;
    |&amp;lt;--- 2. Returns JWT (Set-Cookie / Body) ------------|&lt;br&gt;
    |                                                    |&lt;br&gt;
    |---- 3. GET /api/dashboard (Bearer ) -------&amp;gt;|&lt;br&gt;
    |                                                    |-- Recomputes signature&lt;br&gt;
    |                                                    |-- Checks exp timestamp&lt;br&gt;
    |                                                    |-- Serves data (Zero DB lookups!)&lt;br&gt;
    |&amp;lt;--- 4. HTTP 200 OK --------------------------------|&lt;br&gt;
Authentication: The client submits credentials to /api/login.&lt;/p&gt;

&lt;p&gt;Issue: The server checks credentials against the database, builds the claims payload, signs it with its secret, and returns the token.&lt;/p&gt;

&lt;p&gt;Storage: The client stores the token (preferably in an httpOnly, Secure, SameSite cookie to mitigate XSS attack vectors).&lt;/p&gt;

&lt;p&gt;Transport: Subsequent calls pass the token via the Authorization header:&lt;/p&gt;

&lt;p&gt;HTTP&lt;br&gt;
Authorization: Bearer eyJhbGciOi...&lt;br&gt;
Stateless Verification: The server recomputes the signature using its secret and checks the exp timestamp. If valid, the request proceeds—without querying a session database.&lt;/p&gt;

&lt;p&gt;Architectural Trade-offs: When NOT to Use Pure JWTs&lt;br&gt;
Statelessness makes horizontal scaling easier, but it introduces tradeoffs that standard tutorials gloss over:&lt;/p&gt;

&lt;p&gt;Feature Session IDs (Stateful)  JWTs (Stateless)&lt;br&gt;
Revocation  Instant (delete record from Redis/DB).  Difficult (valid until exp triggers).&lt;br&gt;
Payload Size    Tiny (~32-character pointer string).    Larger (carries claims on every request).&lt;br&gt;
DB / Cache Load Hit on every authenticated request. Zero DB lookups for validation.&lt;br&gt;
Server Sync Requires shared session store.  Any service with the key/public key can verify.&lt;br&gt;
The Revocation Problem&lt;br&gt;
If a user changes their password, reports a compromised account, or gets suspended, an issued JWT remains completely valid until its exp time passes.&lt;/p&gt;

&lt;p&gt;To fix this in production, architectures commonly use:&lt;/p&gt;

&lt;p&gt;Short-lived access tokens (5–15 minutes) combined with stateful refresh tokens stored securely in a database.&lt;/p&gt;

&lt;p&gt;Revocation blocklists in Redis (which sacrifices pure statelessness).&lt;/p&gt;

&lt;p&gt;Core Takeaways&lt;br&gt;
Base64Url is encoding, not encryption. Don't hide secrets in the payload.&lt;/p&gt;

&lt;p&gt;Signatures ensure integrity, not secrecy. They only prove the data hasn't been modified.&lt;/p&gt;

&lt;p&gt;Statelessness is a double-edged sword. Build an explicit revocation strategy before relying on JWTs in production.&lt;/p&gt;

&lt;p&gt;Over to you: How does your team handle token invalidation? Are you pairing short-lived access tokens with refresh tokens, or relying on centralized session stores like Redis? Let's discuss in the comments below!&lt;/p&gt;

</description>
      <category>authentication</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Beyond the Monolith: A Practical Guide to Database Sharding</title>
      <dc:creator>CHRISTIAN OTIENO</dc:creator>
      <pubDate>Sat, 29 Aug 2026 10:37:56 +0000</pubDate>
      <link>https://dev.to/christian-otieno/beyond-the-monolith-a-practical-guide-to-database-sharding-5eb</link>
      <guid>https://dev.to/christian-otieno/beyond-the-monolith-a-practical-guide-to-database-sharding-5eb</guid>
      <description>&lt;p&gt;Table Of Contents&lt;br&gt;
1.Introduction: When Scaling Up Hits a Wall&lt;br&gt;
2.What Is Database Sharding?&lt;br&gt;
3.Core Sharding Architectures &amp;amp; Routing Strategies&lt;br&gt;
4.The Operational Hidden Costs of Sharding&lt;br&gt;
5.When Should You Actually Shard?&lt;br&gt;
6.Conclusion&lt;/p&gt;

&lt;p&gt;Introduction: When Scaling Up Hits a Wall&lt;/p&gt;

&lt;p&gt;Every growing application eventually hits a point where vertical scaling—throwing more CPU, RAM, and faster NVMe drives at a single database instance—stops being economically or physically viable. When your primary relational database hits storage limits, IOPS bottlenecks, or connection pool saturation, horizontal scaling becomes the inevitable next step.&lt;/p&gt;

&lt;p&gt;Enter database sharding.&lt;/p&gt;

&lt;p&gt;While sharding solves massive throughput and storage constraints, it introduces a whole new class of distributed systems complexities. Let's break down how sharding actually works, the architectural patterns you can choose, and the hidden operational costs you need to weigh before splitting your data.&lt;/p&gt;

&lt;p&gt;What Is Database Sharding?&lt;/p&gt;

&lt;p&gt;At its core, sharding is a shared-nothing horizontal partitioning strategy. Instead of keeping all rows of a massive table in a single database instance, you split the rows across multiple independent databases (called "shards").&lt;/p&gt;

&lt;p&gt;Each shard holds a subset of the total data, and the union of all shards makes up the complete dataset.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;           [ Application / Router Layer ]
          /              |              \
         /               |               \
        v                v                v
  [ Shard 1 ]      [ Shard 2 ]      [ Shard 3 ]
 (Users A-H)      (Users I-P)      (Users Q-Z)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Unlike read replicas (which duplicate the entire dataset for read scaling), shards actively partition write and storage workloads, allowing your infrastructure to scale out linearly.&lt;/p&gt;

&lt;p&gt;Core Sharding Architectures &amp;amp; Routing Strategies&lt;/p&gt;

&lt;p&gt;How do you decide which shard a piece of data belongs to? Your routing strategy dictates how queries find their target nodes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Range-Based Sharding&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Data is partitioned based on predefined ranges of a column value. For example, user IDs 1 to 1,000,000 go to Shard A, and 1,000,001 to 2,000,000 go to Shard B.&lt;/p&gt;

&lt;p&gt;Pros: Simple to implement; highly efficient for range queries (e.g., WHERE created_at BETWEEN ...).&lt;br&gt;
Cons: Prone to hotspotting. If most of your incoming traffic targets newly created users, Shard B will absorb 90% of the write load while older shards sit idle.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hash-Based Sharding&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An application or database proxy passes a sharding key (like a user_id or tenant_id) through a hash function (such as MurmurHash), and applies a modulo operation to determine the target shard index.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conceptual hash routing example
&lt;/h1&gt;

&lt;p&gt;shard_count = 4&lt;br&gt;
user_id = 849203&lt;br&gt;
shard_index = hash(user_id) % shard_count&lt;br&gt;
Pros: Evenly distributes data and write load across all available shards, eliminating hotspots.&lt;br&gt;
Cons: Extremely painful to scale out. If you add a fifth shard, changing the modulo math requires a massive data migration (re-sharding) to redistribute existing keys. (Consistent hashing algorithms help mitigate this, but add architectural overhead).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Directory-Based Sharding&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You maintain a centralized lookup table (or service) that tracks which entity lives on which shard.&lt;/p&gt;

&lt;p&gt;Pros: Highly flexible; you can manually move individual tenants or users to different shards for load balancing.&lt;br&gt;
Cons: The directory lookup becomes a single point of failure (SPOF) and an extra network hop for every single query.&lt;/p&gt;

&lt;p&gt;The Operational Hidden Costs of Sharding&lt;/p&gt;

&lt;p&gt;Before you commit to sharding your database, you must accept the distributed systems trade-offs. Sharding breaks several guarantees that monolithic SQL databases provide out-of-the-box:&lt;/p&gt;

&lt;p&gt;Cross-Shard Joins are Painful: If users live on Shard 1 and their corresponding orders live on Shard 2, joining those tables requires application-level orchestration, scatter-gather queries, or distributed transactions (two-phase commit), which heavily degrades performance.&lt;/p&gt;

&lt;p&gt;Global Uniqueness Constraints: Enforcing a unique constraint (like an email address or username) across multiple independent databases requires a centralized ID generation service (like Twitter Snowflake or centralized Redis counters).&lt;/p&gt;

&lt;p&gt;Re-balancing and Resharding: As your data grows unevenly, splitting an overloaded shard into two requires careful planning, dual-writes, and zero-downtime data migration pipelines.&lt;/p&gt;

&lt;p&gt;When Should You Actually Shard?&lt;/p&gt;

&lt;p&gt;The golden rule of database sharding is simple: Don't do it until you absolutely have to.&lt;/p&gt;

&lt;p&gt;Exhaust all other optimization paths first:&lt;/p&gt;

&lt;p&gt;Optimize your indexing and query execution plans.&lt;br&gt;
Implement aggressive caching layers (e.g., Redis or Memcached).&lt;br&gt;
Offload read traffic using read replicas.&lt;br&gt;
Purge or archive cold/historical data into cheaper cold storage.&lt;br&gt;
If you have genuinely maxed out vertical scaling, saturated your primary write IOPS, and your dataset spans hundreds of gigabytes or terabytes where partitioning by tenant makes logical sense—then sharding is your answer.&lt;/p&gt;

&lt;p&gt;How does your team handle database scaling bottlenecks? Have you ever migrated a monolith to a sharded architecture, and what was your biggest lesson learned? Let me know in the comments below!&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>database</category>
      <category>performance</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>AI Can Build Your UI—But Can It Maintain It?</title>
      <dc:creator>CHRISTIAN OTIENO</dc:creator>
      <pubDate>Wed, 17 Jun 2026 17:42:02 +0000</pubDate>
      <link>https://dev.to/christian-otieno/ai-can-build-your-ui-but-can-it-maintain-it-16lh</link>
      <guid>https://dev.to/christian-otieno/ai-can-build-your-ui-but-can-it-maintain-it-16lh</guid>
      <description>&lt;p&gt;AI coding agents have moved way past simple autocomplete. Anyone can prompt an agent to build a clean dashboard component. But what happens six months later when dependencies shift, state management gets tangled, or accessibility breaks?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>discuss</category>
    </item>
    <item>
      <title>ASCII ART</title>
      <dc:creator>CHRISTIAN OTIENO</dc:creator>
      <pubDate>Wed, 17 Jun 2026 17:29:45 +0000</pubDate>
      <link>https://dev.to/christian-otieno/ascii-art-48n3</link>
      <guid>https://dev.to/christian-otieno/ascii-art-48n3</guid>
      <description>&lt;p&gt;Why ASCII Art is Still the Ultimate Dev Nostalgia.&lt;br&gt;
If you’ve ever opened a new terminal tool, checked a repository's README.md, or looked closely at a well-documented source code file, chances are you’ve run into ASCII art.&lt;/p&gt;

&lt;p&gt;While it feels like a relic of the 1980s BBS board era, this text-based design medium is still alive, kicking, and surprisingly practical in modern development.&lt;/p&gt;

&lt;p&gt;What is ASCII Art?&lt;br&gt;
At its core, ASCII art is a graphic design technique that uses printable characters from the ASCII standard (letters, numbers, and symbols like /, \, |, _) to piece together visual images.&lt;/p&gt;

&lt;p&gt;Before high-resolution displays and modern GPUs, this was how developers added personality, logos, and diagrams to text-only screens.&lt;/p&gt;

&lt;p&gt;Why Do Developers Still Use It?&lt;br&gt;
Zero Overhead: It requires no image hosting, no external assets, and zero loading time. It’s just plain text.&lt;/p&gt;

&lt;p&gt;Terminal Branding: Popular CLI tools (like Homebrew, Docker, or Neofetch) use ASCII splash screens to build an instant, recognizable brand right in your terminal.&lt;/p&gt;

&lt;p&gt;Code Organization: Massive codebases sometimes use giant ASCII headers to separate major sections in a single source file, making it easy to spot sections while scrolling fast.&lt;/p&gt;

&lt;p&gt;Pure Nostalgia: Let’s honest—it just looks incredibly cool and gives off peak hacker vibes.&lt;/p&gt;

&lt;p&gt;Quick Tools to Generate Your Own&lt;br&gt;
You don’t have to manually type out every backslash. Here are the quickest ways to add some flavor to your next project:&lt;/p&gt;

&lt;p&gt;FIGlet: A classic command-line tool that turns ordinary text into large, stylized ASCII banners.&lt;/p&gt;

&lt;p&gt;TAAG (Text to ASCII Art Generator): An awesome web-based tool with hundreds of fonts to preview your text instantly.&lt;/p&gt;

&lt;p&gt;Image-to-ASCII Converters: Tools like jp2a can take an actual .jpg or .png logo and translate it into a grayscale-like block of text.&lt;/p&gt;

&lt;p&gt;The Takeaway&lt;br&gt;
ASCII art is a bridge between computing's past and present. Next time you build an open-source tool, consider throwing a custom ASCII logo into your README or CLI startup script. It’s a small, fun touch that shows you care about the details.&lt;/p&gt;

&lt;p&gt;Do you use ASCII art in your project configs or CLIs? Drop your favorite generator or your terminal setups in the comments below!&lt;/p&gt;

</description>
      <category>zone01kisumu</category>
      <category>softwaredevelopment</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
