<?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: Srinivas Mekala</title>
    <description>The latest articles on DEV Community by Srinivas Mekala (@srinivas1227).</description>
    <link>https://dev.to/srinivas1227</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%2F2471430%2Fcc8d30bf-9e0a-4ff1-90f5-54e8171869b6.jpeg</url>
      <title>DEV Community: Srinivas Mekala</title>
      <link>https://dev.to/srinivas1227</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/srinivas1227"/>
    <language>en</language>
    <item>
      <title>Learning Odin - Installation and Hello World! Program</title>
      <dc:creator>Srinivas Mekala</dc:creator>
      <pubDate>Wed, 15 Jul 2026 04:16:19 +0000</pubDate>
      <link>https://dev.to/srinivas1227/learning-odin-installation-and-hello-world-program-373</link>
      <guid>https://dev.to/srinivas1227/learning-odin-installation-and-hello-world-program-373</guid>
      <description>&lt;h2&gt;
  
  
  Learning Challenge - Day 1/50
&lt;/h2&gt;

&lt;p&gt;This is a 50 Days challenge to learn something new everyday for 45Mins without relying much on AI.&lt;/p&gt;

&lt;p&gt;Started Odin Programming Language and I'm promising my future self that I'll build something exciting with Odin by the end of this &lt;strong&gt;Challenge&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;I'm working on my HomeServer (Ubuntu Server) by connecting remotely to my VSCode on my Windows Machine. So, everything will be same as I'm using a linux machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Essentials
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;em&gt;clang, llvm and llvm-devel&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why?&lt;/strong&gt; Check the note after the commands
&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;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get upgrade
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;clang llvm llvm-devel build-essential
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Close the terminal and open a new one&lt;/li&gt;
&lt;li&gt;Verify the installations
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;clang &lt;span class="nt"&gt;--version&lt;/span&gt;
llvm-config &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Installing Odin now
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Clone the official Odin from GitHub by
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/odin-lang/Odin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;cd to the directory and make the install
&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;cd &lt;/span&gt;Odin
make release-native
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;To made odin available from anywhere to run it as an executable. Export the path to your bashrc or zshrc
&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;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH="/full/path/to/Odin/folder:$PATH"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc &lt;span class="o"&gt;(&lt;/span&gt;or&lt;span class="o"&gt;)&lt;/span&gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Refer and follow &lt;a href="https://odin-lang.org/docs/install/" rel="noopener noreferrer"&gt;Official Documentation&lt;/a&gt; if you're confused or see any errors&lt;/p&gt;

&lt;h2&gt;
  
  
  Hello World!
&lt;/h2&gt;

&lt;p&gt;👏🏻🎉 Yay! If you reached here without any issues. You've successfully installed Odin language and we're ready to go.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a Project Folder
&lt;code&gt;mkdir learn-odin &amp;amp;&amp;amp; cd learn-odin&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;create a file named &lt;code&gt;.odin&lt;/code&gt; and add the following code
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"core:fmt"&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello World!"&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;ul&gt;
&lt;li&gt;Run the program &lt;code&gt;odin run ./&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fujyibv672vfhbchvic1n.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fujyibv672vfhbchvic1n.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Odin by default thinks in terms of directory-based packages and it expects a .odin file for that directory. So, when we run, it compiles all the files in that directory into a package and then tunrs that into an executable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alternatively, if we want to create a single odin and run it as a file. Rename or create a new file say &lt;code&gt;hello-world.odin&lt;/code&gt; and with the same code inside the file, run &lt;code&gt;odin run hello-world.odin -file&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbns0pfxmzoexzr0ipn0u.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbns0pfxmzoexzr0ipn0u.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Voila! We just wrote our first Odin file and executed it. &lt;strong&gt;Yay!&lt;/strong&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;PS: Hey That's a good start. We still don't know what's a package. Why we're import &lt;code&gt;core:fmt&lt;/code&gt; and what those two colons (::) are and what actually the code means.&lt;br&gt;
Let's worry about in the next one.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>odinprogramminglanguage</category>
      <category>learning</category>
      <category>odinlang</category>
      <category>devchallenge</category>
    </item>
    <item>
      <title>Cookies or Bearer Tokens? The Day my Auth Design Decision Broke.</title>
      <dc:creator>Srinivas Mekala</dc:creator>
      <pubDate>Sat, 11 Jul 2026 16:20:13 +0000</pubDate>
      <link>https://dev.to/srinivas1227/cookies-or-bearer-tokens-the-day-my-auth-design-decision-broke-178l</link>
      <guid>https://dev.to/srinivas1227/cookies-or-bearer-tokens-the-day-my-auth-design-decision-broke-178l</guid>
      <description>&lt;p&gt;It's been 3 months since I was actively building &lt;a href="https://mystashd.link" rel="noopener noreferrer"&gt;StashD&lt;/a&gt; -- a link-organizing app. NextJs on the frontend, Flask + MongoDB on the backend. Auth was one of the first things I had to get right, so I did what felt like the "correct" thing at the time: httpOnly cookies. Secure, invisible to JavaScript, browser handles everything for me. I shipped it, moved on, felt good about the decision.&lt;/p&gt;

&lt;p&gt;Today, I thought, why don't I build a mobile app so my users can access their saved links from their phones on demand.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Moment It Fell Apart
&lt;/h2&gt;

&lt;p&gt;I sat down to think through how the mobile app would authenticate, researched a lil bit, and it hit me in the face: &lt;strong&gt;there's no browser cookie jar on a native app🤦🏻‍♂️.&lt;/strong&gt; My entire auth flow assumed a browser sitting between the user and my API — one that would store a cookie and automatically reattach it on every request without me writing a line of code for it. That assumption had been invisible to me the whole time I was building for web only, because it was just... always true. Every request from the browser already carried the cookie. I never had to think about the mechanism, so I never noticed I'd built a dependency on it.&lt;/p&gt;

&lt;p&gt;A mobile app doesn't get that for free. There's no automatic anything. If I wanted the Android app to authenticate against the same Flask API, I'd need to manually attach a token to every request myself. Which meant my whole "cookie is the auth mechanism" design was actually "cookie is &lt;em&gt;a&lt;/em&gt; auth mechanism, coupled to exactly one client — the browser."&lt;/p&gt;

&lt;p&gt;That was the first real &lt;strong&gt;lesson&lt;/strong&gt;: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An auth design that only works because of an environment-specific behavior isn't a design, it's an accident that happens to work in one place.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  It's Time to Rewind the Reel
&lt;/h2&gt;

&lt;p&gt;I had to stop and actually understand &lt;em&gt;why&lt;/em&gt; I picked cookies in the first place, instead of just knowing that I had. Here's what I worked out.&lt;/p&gt;

&lt;p&gt;A cookie and a bearer token carry the same thing — a JWT. The difference is entirely about &lt;em&gt;who attaches it to a request&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cookie&lt;/strong&gt;: the browser attaches it automatically, for every request matching the cookie's domain. I don't have to write the attachment logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bearer token&lt;/strong&gt;: my code does it, manually, via an &lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt; header. Nothing happens unless I write that line.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. That's the whole difference. But that one difference cascades into everything else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Did I pick Cookies blindly? No!:&lt;/strong&gt; _httpOnly _cookies can't be read by page JavaScript. If someone ever manages to inject a malicious script into my site (XSS), that script &lt;em&gt;cannot&lt;/em&gt; steal the token — it's invisible to &lt;code&gt;document.cookie&lt;/code&gt;. If I had instead put my JWT in &lt;code&gt;localStorage&lt;/code&gt;, any XSS bug becomes a full account takeover, and the stolen token is portable — usable from the attacker's own machine, forever, until it expires.&lt;/p&gt;

&lt;p&gt;That's a real, good reason to prefer cookies. I took it as "best practice" without connecting it to the actual mobile-shaped hole in the design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But cookies aren't free.&lt;/strong&gt; Because the browser attaches them automatically, a malicious site can trick a victim's browser into firing a request at my API with the cookie riding along — that's CSRF. Next.js comes to the rescue here: it defaults cookies to &lt;code&gt;SameSite=Lax&lt;/code&gt;, which blocks that for state-changing requests.&lt;/p&gt;

&lt;p&gt;Bearer tokens flip both properties. Immune to CSRF by construction — there's no ambient credential for a third-party site to hijack, since nothing is attached automatically. But if the token sits in &lt;code&gt;localStorage&lt;/code&gt; or a JS variable, XSS &lt;em&gt;can&lt;/em&gt; read it directly, and now it's stolen, not just abused-in-session.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Neither one is "more secure" in the abstract. They're secure against &lt;em&gt;different things&lt;/em&gt;, and the win depends entirely on the shape of your client.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  My Second Lesson: What do I change to support both mobile and web requests?
&lt;/h2&gt;

&lt;p&gt;My first plan was: keep cookies for web, add a second code path in Flask that also accepts a bearer header for mobile. Check cookie first, fall back to header. Felt like the minimal change.&lt;/p&gt;

&lt;p&gt;It would have worked. But sitting with it a bit longer, I realized I was about to bake "what kind of client is calling me" into my backend's auth logic, permanently, for every route, forever. Two paths to test, two paths to audit for security holes, and the set only grows if I ever add a third client.&lt;/p&gt;

&lt;p&gt;The better shape, once I saw it: &lt;strong&gt;the backend shouldn't know or care what kind of client is calling it.&lt;/strong&gt; Make the API bearer-only, full stop. It returns a token in the response body on login, and validates one thing — the &lt;code&gt;Authorization&lt;/code&gt; header — on every protected route. No branching.&lt;/p&gt;

&lt;p&gt;Then the &lt;em&gt;cookie&lt;/em&gt; isn't a backend concern at all anymore. It becomes something the &lt;strong&gt;web app does to itself&lt;/strong&gt; — my Next.js server receives that bearer token same as any other client would, and wraps it in its own httpOnly cookie before it ever reaches the browser. When the web server needs to call the API on the user's behalf, it just reads its own cookie back out and forwards it as a bearer header. The Flask API never even knows a cookie existed anywhere in the chain.&lt;/p&gt;

&lt;p&gt;The mobile app does the same thing, minus the cookie step — takes the token from the response body, drops it straight into secure device storage (Keystore-backed on Android), attaches it as a bearer header on every call. No intermediary needed, because a native app doesn't have the XSS threat model a browser has in the first place.&lt;/p&gt;

&lt;p&gt;Two clients, two completely different ideas of "how do I protect this token" — and the backend doesn't have to know either one exists. That's the part I actually feel good about: not "I added mobile support," but "I found the layer where the client-specific decision actually belongs, and moved it there."&lt;/p&gt;




&lt;p&gt;PS: Try out my WebApp : &lt;a href="https://mystashd.link" rel="noopener noreferrer"&gt;StashD&lt;/a&gt;.&lt;br&gt;
Hope you like it and wait for the mobile version too.🫡✌🏻&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>mobile</category>
      <category>security</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
