<?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: Turkay Kalenci</title>
    <description>The latest articles on DEV Community by Turkay Kalenci (@turkaykalenci).</description>
    <link>https://dev.to/turkaykalenci</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%2F3608448%2F5a2abf7e-e988-4023-8516-96f8c5e9a443.png</url>
      <title>DEV Community: Turkay Kalenci</title>
      <link>https://dev.to/turkaykalenci</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/turkaykalenci"/>
    <language>en</language>
    <item>
      <title>An Ultimate Guide to Debugging JWTs in Your Web App</title>
      <dc:creator>Turkay Kalenci</dc:creator>
      <pubDate>Wed, 12 Nov 2025 17:34:06 +0000</pubDate>
      <link>https://dev.to/turkaykalenci/an-ultimate-guide-to-debugging-jwts-in-your-web-app-g64</link>
      <guid>https://dev.to/turkaykalenci/an-ultimate-guide-to-debugging-jwts-in-your-web-app-g64</guid>
      <description>&lt;p&gt;As developers, we are often forced to treat JSON Web Tokens (JWTs) as "magic black boxes." We get them from the auth server, stick them in a "Bearer" header, and pray.&lt;/p&gt;

&lt;p&gt;The moment we see {"error": "Invalid Token"}, we panic.&lt;/p&gt;

&lt;p&gt;Is it expired? Is the signature wrong? Is the server down? This guide will turn that black box into a clear glass box. This is a systematic process for debugging any JWT problem.&lt;/p&gt;

&lt;p&gt;ANATOMY OF A JWT (THE 30-SECOND REFRESHER)&lt;br&gt;
A JWT is just three strings, separated by dots: xxxx.yyyyy.zzzz&lt;/p&gt;

&lt;p&gt;HEADER: Contains the algorithm (e.g., HS256).&lt;/p&gt;

&lt;p&gt;PAYLOAD: Contains the data (e.g., userId, iat (Issued At), exp (Expiration Time)).&lt;/p&gt;

&lt;p&gt;SIGNATURE: Ensures the token wasn't tampered with.&lt;/p&gt;

&lt;p&gt;The Header and Payload are just Base64-encoded JSON. They are not encrypted. They are public.&lt;/p&gt;

&lt;p&gt;THE DEBUGGING FLOWCHART: A STEP-BY-STEP GUIDE&lt;br&gt;
Stop guessing. Follow this process.&lt;/p&gt;

&lt;p&gt;STEP 1: IS IT BEING SENT? Before anything else, open your browser's Network tab.&lt;/p&gt;

&lt;p&gt;Find your failed API request (it will be red, usually a 401 or 403 status).&lt;/p&gt;

&lt;p&gt;Click on it. Go to the "Headers" tab.&lt;/p&gt;

&lt;p&gt;Look at "Request Headers." Do you see Authorization: Bearer [long string]?&lt;/p&gt;

&lt;p&gt;If not, your front-end code is failing to attach the token. Your token isn't "invalid," it's "missing."&lt;/p&gt;

&lt;p&gt;STEP 2: IS IT MALFORMED? (THE MANUAL DECODE) If the token is being sent, copy that long string (without the "Bearer" part). Now, you need to see what's inside. Manually copying the middle part (the Payload) and pasting it into a generic Base64 decoder is slow and clunky.&lt;/p&gt;

&lt;p&gt;This is why a dedicated JWT Debugger is essential. For my own workflow, I use a simple online tool (like the one at toolunify.com/en/encoder-decoder/jwt-debugger/) which instantly decodes the Header and Payload JSON for me.&lt;/p&gt;

&lt;p&gt;Check the decoded payload. Is the JSON valid? Does it have the userId or sub (Subject) claim you expect?&lt;/p&gt;

&lt;p&gt;STEP 3: IS IT EXPIRED? In that decoded payload, find the exp claim. It will look like this: 1678886400. This is a Unix timestamp. Go to a Unix Time converter (like the one in the toolunify.com suite) and check that date. If that time is in the past, your token is expired. Your front-end code needs to use its "refresh token" to get a new one.&lt;/p&gt;

&lt;p&gt;STEP 4: IS THE SIGNATURE VALID? If the token is sent, is not malformed, and is not expired, then the only remaining option is a failed signature. This is a backend problem. This means the server (which has the "secret key") tried to verify the token and failed. This usually happens in two cases:&lt;/p&gt;

&lt;p&gt;The token was tampered with on the client-side.&lt;/p&gt;

&lt;p&gt;The server's secret key is wrong (e.g., dev and prod keys don't match).&lt;/p&gt;

&lt;p&gt;CONCLUSION: STOP TREATING AUTH AS MAGIC&lt;br&gt;
By following this flowchart, you've systematically ruled out every possibility.&lt;/p&gt;

&lt;p&gt;Check Network Tab (Is it sent?)&lt;/p&gt;

&lt;p&gt;Check Payload (Is it malformed?)&lt;/p&gt;

&lt;p&gt;Check exp claim (Is it expired?)&lt;/p&gt;

&lt;p&gt;If all else fails, blame the backend (Invalid Signature).&lt;/p&gt;

&lt;p&gt;Stop guessing, and start debugging.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Base64 Dilemma: When (and How) to Actually Inline Images in CSS</title>
      <dc:creator>Turkay Kalenci</dc:creator>
      <pubDate>Wed, 12 Nov 2025 17:33:38 +0000</pubDate>
      <link>https://dev.to/turkaykalenci/the-base64-dilemma-when-and-how-to-actually-inline-images-in-css-2i9p</link>
      <guid>https://dev.to/turkaykalenci/the-base64-dilemma-when-and-how-to-actually-inline-images-in-css-2i9p</guid>
      <description>&lt;p&gt;We’ve all heard the advice: "Inline your small images into CSS using Base64! It saves an HTTP request!" It sounds like a clear performance win.&lt;/p&gt;

&lt;p&gt;I took this advice to heart on a recent project. I dutifully converted all my small SVG icons into Base64 strings and embedded them directly into my main stylesheet.&lt;/p&gt;

&lt;p&gt;Then I ran Lighthouse. My performance score had tanked.&lt;/p&gt;

&lt;p&gt;My "optimized" CSS file had ballooned to over 1.5MB, completely blocking the page render. This was the "lived experience" that forced me to learn the real trade-offs of Base64 inlining.&lt;/p&gt;

&lt;p&gt;This isn't just "what is Base64." This is the practical guide I wish I had found on Google when I was trying to figure out what went wrong.&lt;/p&gt;

&lt;p&gt;THE REAL-WORLD TRADE-OFFS&lt;br&gt;
We need to compare four critical metrics: HTTP Requests, File Size, Rendering, and Caching.&lt;/p&gt;

&lt;p&gt;HTTP REQUESTS This is the obvious one. Base64 wins. By inlining the image, you save a network request for each asset. Fewer requests are good. But at what cost?&lt;/p&gt;

&lt;p&gt;FILE SIZE This is the first trap. Base64 encoding is not efficient. It takes binary data (the image) and converts it into text, which increases the file size by roughly 33%. That 2KB icon? It's now about 2.7KB inside your CSS file. This adds up fast.&lt;/p&gt;

&lt;p&gt;RENDERING (THE HIDDEN KILLER) This is what destroyed my Lighthouse score. A browser must download and parse a CSS file before it can paint the page (it's "render-blocking").&lt;/p&gt;

&lt;p&gt;SCENARIO A (External): style.css (100KB) + 5 small icons (2KB each, 10KB total). The 100KB CSS loads fast. The icons load asynchronously. The page renders quickly.&lt;/p&gt;

&lt;p&gt;SCENARIO B (Inlined): style.css (100KB + 13.5KB from 5 inlined icons) = 113.5KB. Now imagine 50 icons. My CSS file became a 1.5MB monster that held the entire page hostage. A fast-loading page with a few async icons is almost always better than a page that waits for one giant, slow-loading CSS file.&lt;/p&gt;

&lt;p&gt;CACHING This is the final nail in the coffin. When an icon is an external file (icon.svg), the browser caches it. If you change your CSS, the icon stays cached. When you inline that icon into your CSS, it becomes part of the CSS file. If you change any line of that CSS (like a color or font size), the entire 1.5MB file must be re-downloaded by the user, including all 50 inlined icons.&lt;/p&gt;

&lt;p&gt;THE "TRICK": MY NEW BEST PRACTICE&lt;br&gt;
After that disaster, I developed a simple 3-question checklist.&lt;/p&gt;

&lt;p&gt;Is the image tiny (e.g., under 2KB)?&lt;/p&gt;

&lt;p&gt;Is the image critical for the initial page load (e.g., a "loading" spinner or an "X" icon for a modal that must be visible immediately)?&lt;/p&gt;

&lt;p&gt;Will this image rarely change?&lt;/p&gt;

&lt;p&gt;If the answer to all three is "Yes," then I'll consider inlining it.&lt;/p&gt;

&lt;p&gt;For everything else? Use modern formats (like .webp or .avif) and let the browser's powerful caching system do its job.&lt;/p&gt;

&lt;p&gt;MY PRACTICAL WORKFLOW&lt;br&gt;
For my build process, I use CLI tools (like openssl base64) to automate this.&lt;/p&gt;

&lt;p&gt;But for quick debugging or testing, I need to grab a string fast. This was one of the frustrations that led me to build my own utility suite. I just use a simple, no-ads online encoder (like the one I built for my own workflow at toolunify.com/en/encoder-decoder/base64/) to grab the string, test it in my CSS, and check the performance impact.&lt;/p&gt;

&lt;p&gt;Base64 is a sharp tool, not a blunt hammer. Use it surgically.&lt;/p&gt;

</description>
      <category>css</category>
      <category>performance</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
