<?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: Seamoon Pandey</title>
    <description>The latest articles on DEV Community by Seamoon Pandey (@seamoonpandey).</description>
    <link>https://dev.to/seamoonpandey</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%2F1029100%2F5a0775c4-c1e5-4162-a0f7-ca67ae2b375a.jpg</url>
      <title>DEV Community: Seamoon Pandey</title>
      <link>https://dev.to/seamoonpandey</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/seamoonpandey"/>
    <language>en</language>
    <item>
      <title>Bloom Filters, Explained Simply</title>
      <dc:creator>Seamoon Pandey</dc:creator>
      <pubDate>Tue, 11 Aug 2026 08:36:09 +0000</pubDate>
      <link>https://dev.to/seamoonpandey/bloom-filters-explained-simply-2l47</link>
      <guid>https://dev.to/seamoonpandey/bloom-filters-explained-simply-2l47</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;A row of bits, all zero. To store something, hash it a few times and flip the slots those hashes point at. To look something up, hash it again and check the same slots.&lt;/p&gt;

&lt;p&gt;Any slot still 0 means it's definitely not there. All slots 1 means probably there, so go check the real database.&lt;/p&gt;

&lt;p&gt;It can only be wrong in one direction: false alarms, never misses. Costs about 10 bits per item for a 1% error rate, so 10 million records fit in roughly 12 MB. It can't list what's in it, can't count, and can't delete.&lt;/p&gt;

&lt;p&gt;Its whole job is killing 99% of expensive lookups before they happen.&lt;/p&gt;

&lt;p&gt;If that already makes sense, you're done. The rest is the same thing slowly, with a worked example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the annoying problem
&lt;/h2&gt;

&lt;p&gt;You're building a signup page. Someone types a username, and you have to tell them whether it's taken.&lt;/p&gt;

&lt;p&gt;Easy. Ask the database.&lt;/p&gt;

&lt;p&gt;The trouble is that you're asking it constantly. Every keystroke in that box turns into a network call and a disk lookup, and you've got a few million users and a lot of visitors. So you're burning real resources to discover, over and over, that "xkq_dragon_9981" is available.&lt;/p&gt;

&lt;p&gt;And it usually is available. That's the part worth noticing. Almost every name someone tries is free, which means almost every one of those expensive lookups was pointless before you even made it.&lt;/p&gt;

&lt;p&gt;What you want is something small and fast sitting in front of the database, catching all the obvious misses so they never reach it.&lt;/p&gt;

&lt;p&gt;That's a Bloom filter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea, in one sentence
&lt;/h2&gt;

&lt;p&gt;It tells you &lt;strong&gt;"definitely not in the set"&lt;/strong&gt; or &lt;strong&gt;"probably in the set."&lt;/strong&gt; Very fast. Almost no memory. And it never stores your actual data.&lt;/p&gt;

&lt;p&gt;Everything below is just how that works and what it costs you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting one up
&lt;/h2&gt;

&lt;p&gt;You need a row of slots, each holding a 0 or a 1. All zeros to start.&lt;/p&gt;

&lt;p&gt;A real one might have millions of slots. We'll use 16, because 16 fits on a screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;index:  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
value:  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You also need hash functions. We'll use three.&lt;/p&gt;

&lt;p&gt;If "hash function" sounds intimidating, it shouldn't. For our purposes it's just a rule that takes any input and spits out a number. It needs two properties and no others:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Same input, same output, always. Feed it &lt;code&gt;"alex"&lt;/code&gt; today and next year and you get the same number both times.&lt;/li&gt;
&lt;li&gt;Different inputs land in different places, spread reasonably evenly across 0 to 15.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. That's the whole job description.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a name
&lt;/h2&gt;

&lt;p&gt;To add &lt;code&gt;"alex"&lt;/code&gt;, run it through all three hash functions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;h1("alex") = 2&lt;/li&gt;
&lt;li&gt;h2("alex") = 7&lt;/li&gt;
&lt;li&gt;h3("alex") = 13&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flip those three slots to 1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;index:  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
value:  0  0  1  0  0  0  0  1  0  0  0  0  0  1  0  0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now add &lt;code&gt;"priya"&lt;/code&gt;. Her hashes give 4, 7, 11.&lt;/p&gt;

&lt;p&gt;Slot 7 is already 1. You just leave it. Nothing anywhere records that two different names are now leaning on that same slot, and that detail is going to matter quite a lot later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;index:  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
value:  0  0  1  0  1  0  0  1  0  0  0  1  0  1  0  0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One more. &lt;code&gt;"sam"&lt;/code&gt; gives 0, 9, 13.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;index:  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
value:  1  0  1  0  1  0  0  1  0  1  0  1  0  1  0  0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three usernames stored.&lt;/p&gt;

&lt;p&gt;Look at what isn't in that row, though. The strings &lt;code&gt;"alex"&lt;/code&gt;, &lt;code&gt;"priya"&lt;/code&gt; and &lt;code&gt;"sam"&lt;/code&gt; appear nowhere. The filter didn't keep them. It kept the marks they left on the way through, and that's a genuinely different thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking something up
&lt;/h2&gt;

&lt;p&gt;Same procedure. Hash the input three times, check those three slots.&lt;/p&gt;

&lt;h3&gt;
  
  
  When some slot is 0
&lt;/h3&gt;

&lt;p&gt;Someone types &lt;code&gt;"maria"&lt;/code&gt;. Hashes give 1, 6, 12.&lt;/p&gt;

&lt;p&gt;Slot 1 is 0.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"maria"&lt;/code&gt; is not taken. Skip the database entirely.&lt;/p&gt;

&lt;p&gt;And that's a certainty, not a guess. Think about why. If &lt;code&gt;"maria"&lt;/code&gt; had ever been added, slot 1 would have been flipped to 1 right then. It's still 0. So she was never added. There's no room in that argument for the filter to be wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  When every slot is 1, and the name really is taken
&lt;/h3&gt;

&lt;p&gt;Someone types &lt;code&gt;"alex"&lt;/code&gt;. Slots 2, 7, 13, all 1.&lt;/p&gt;

&lt;p&gt;Probably taken. You go query the database, it confirms, you show the "sorry, try another" message. The filter did its job and routed the check where it belonged.&lt;/p&gt;

&lt;h3&gt;
  
  
  When every slot is 1, and the name is actually free
&lt;/h3&gt;

&lt;p&gt;Someone types &lt;code&gt;"jordan"&lt;/code&gt;. Hashes give 0, 4, 13.&lt;/p&gt;

&lt;p&gt;All three are 1.&lt;/p&gt;

&lt;p&gt;Except nobody ever added &lt;code&gt;"jordan"&lt;/code&gt;. Slot 0 came from &lt;code&gt;"sam"&lt;/code&gt;. Slot 4 from &lt;code&gt;"priya"&lt;/code&gt;. Slot 13 from &lt;code&gt;"alex"&lt;/code&gt;. Three unrelated names happened to cover exactly the three slots that &lt;code&gt;"jordan"&lt;/code&gt; checks, and the filter has no way to tell the difference.&lt;/p&gt;

&lt;p&gt;So it says "probably taken," you query the database, the database says no such user, and you tell the person the name is free.&lt;/p&gt;

&lt;p&gt;You made one unnecessary lookup. That's it. That's the whole price of being wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule everything hangs on
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;"No" is always right. "Yes" only means "maybe."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A Bloom filter can produce a false positive. It cannot produce a false negative. It will never tell you something is absent when it's actually sitting right there.&lt;/p&gt;

&lt;p&gt;That lopsidedness isn't a flaw nobody got around to fixing. It's the trade. You accept a handful of wasted lookups, and you get back a structure small enough to live in memory and fast enough to check in nanoseconds.&lt;/p&gt;

&lt;p&gt;One thing follows from this that people miss, so it's worth saying flatly: a Bloom filter is only useful when something trustworthy sits behind it. It screens. It doesn't decide. Every "maybe" has to go somewhere that knows the real answer. Used on its own, with nothing to verify against, it's just a machine that's confidently wrong every so often.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why anyone accepts occasional wrong answers
&lt;/h2&gt;

&lt;p&gt;The numbers.&lt;/p&gt;

&lt;p&gt;Take 10 million usernames. Store them properly at roughly 20 bytes apiece and you're at 200 MB, and that's before you build any kind of index on top to search them quickly.&lt;/p&gt;

&lt;p&gt;Put them in a Bloom filter at 10 bits per entry and you get about a 1% false positive rate using 12.5 MB.&lt;/p&gt;

&lt;p&gt;So 12.5 MB of memory kills 99% of your database traffic. That's not a tuning improvement. It's a different kind of answer to the question.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two dials
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Slots.&lt;/strong&gt; More slots, fewer accidental overlaps, fewer false positives, more memory. Nothing surprising.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hash functions.&lt;/strong&gt; This one is not "more is better," and it catches people out.&lt;/p&gt;

&lt;p&gt;Use only one and a single collision produces a false positive. Too fragile.&lt;/p&gt;

&lt;p&gt;Use fifty and every insert flips fifty slots. The array fills with 1s almost instantly, and once nearly everything is a 1, everything looks like a maybe. A saturated filter says "probably yes" to every question you ask it, which makes it precisely as useful as having no filter at all.&lt;/p&gt;

&lt;p&gt;The sweet spot is roughly "flip enough bits that the array ends up about half full." In numbers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bits per item&lt;/th&gt;
&lt;th&gt;Hash functions&lt;/th&gt;
&lt;th&gt;False positive rate&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;~9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;~2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;~0.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;~0.05%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In practice you won't work this out by hand. You tell the library how many items you expect and what error rate you can live with, and it picks both dials for you. But it's worth knowing the shape of that table, if only so you can tell whether what you're asking for is reasonable before you ask.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it can't do
&lt;/h2&gt;

&lt;p&gt;Worth being blunt here, because people reach for Bloom filters and then get irritated that they aren't hash tables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It can't tell you what's in it.&lt;/strong&gt; You can't ask which usernames it knows about. It holds bits. There is nothing to read back out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It can't count.&lt;/strong&gt; Slot 7: flipped once, or ten thousand times? No idea. The filter has no opinion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It can't delete.&lt;/strong&gt; Say you want to remove &lt;code&gt;"alex"&lt;/code&gt; and you go reset slots 2, 7 and 13. You've just broken &lt;code&gt;"priya"&lt;/code&gt;, who needs slot 7, and &lt;code&gt;"sam"&lt;/code&gt;, who needs slot 13. Now the filter starts saying "definitely not present" about names that are present, and the moment "no" stops being trustworthy the entire structure is worthless. If you need removal, look at counting Bloom filters (a small counter in each slot instead of a single bit) or cuckoo filters (a newer alternative that handles deletion and is often smaller anyway). Both cost you something.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It goes bad quietly.&lt;/strong&gt; Size a filter for 10 million entries, feed it 100 million, and it saturates. Every answer becomes "maybe." It won't throw an error. It won't log a warning. It just stops being useful while continuing to look like it's working fine, which is honestly the failure mode to actually watch for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where these show up
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Databases skipping disk reads.&lt;/strong&gt; By a wide margin the most common real use. Cassandra, HBase, RocksDB and friends spread data across many files on disk, and checking every file for a key is slow. So each file carries a Bloom filter of its own keys. "Definitely not in here" means skip the file completely, no disk read at all. Structurally it's the exact same problem as the signup form: cheap check first, expensive check only if you have to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Browsers checking for dangerous URLs.&lt;/strong&gt; Shipping the full list of known malicious sites to every browser isn't practical. Ship a compact filter instead. Anything that comes back "definitely safe" resolves locally in an instant, and only the rare maybe goes to a server. Nice side effect: most of your browsing history never leaves your machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Caches ignoring one hit wonders.&lt;/strong&gt; A big chunk of CDN requests are for things nobody will ever ask for twice, and caching those is wasted space. So keep a filter of what you've seen once, and only bother caching something on the second request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Blockchain clients.&lt;/strong&gt; Every Ethereum block header carries a 2048 bit Bloom filter summarising the log addresses and topics inside that block. A client hunting for events from one particular contract checks the header filter and skips the entire block on a "no," instead of parsing every transaction since genesis.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, when should you reach for one?
&lt;/h2&gt;

&lt;p&gt;Three conditions, and you want all three.&lt;/p&gt;

&lt;p&gt;You're doing a lot of lookups against a big set. Most of those lookups come back negative. And there's something slow behind the check, a disk, a network call, another service, that you'd like to stop bothering.&lt;/p&gt;

&lt;p&gt;Hit all three and a Bloom filter is close to free money. Miss one and it's probably not worth the complexity. If your set is small enough to sit in a hash table, use the hash table. If most lookups are hits anyway, the filter is just extra work in front of a query you were going to make regardless.&lt;/p&gt;

&lt;p&gt;The mental model that sticks: it's a bouncer, not a judge. Turns away the obvious no's instantly, waves everything else through to someone who actually knows.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Burton Bloom published this in 1970, in a paper about hyphenation in typesetting software. It now holds up databases, browsers and blockchains. Simple ideas tend to outlast clever ones.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>database</category>
      <category>performance</category>
    </item>
    <item>
      <title>My laptop told me to load the kernel first, so I did (a missing-kernel horror story on EndeavourOS)</title>
      <dc:creator>Seamoon Pandey</dc:creator>
      <pubDate>Mon, 22 Jun 2026 09:24:26 +0000</pubDate>
      <link>https://dev.to/seamoonpandey/my-laptop-told-me-to-load-the-kernel-first-so-i-did-a-missing-kernel-horror-story-on-endeavouros-58m8</link>
      <guid>https://dev.to/seamoonpandey/my-laptop-told-me-to-load-the-kernel-first-so-i-did-a-missing-kernel-horror-story-on-endeavouros-58m8</guid>
      <description>&lt;p&gt;So I rebooted my machine like a normal person and got slapped with a blue GRUB screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;error: file '/boot/vmlinuz-linux-lts' not found.
you need to load the kernel first
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cool. Very helpful. Load the kernel first. With what, GRUB? My good looks?&lt;/p&gt;

&lt;p&gt;I dived deep into the issue just to find this was a pretty common issue caused due to some update cancellations in between update sessions breaking the packages(most probably a patience issue) as well as spent almost  an extra of about half an hour session with my claude for more specific information on the issue or rather solution.&lt;/p&gt;

&lt;p&gt;If you're reading this because you got the same message, good news: your system is almost certainly fine and you do not need to reinstall anything. I went through the full panic arc so you don't have to, and here's roughly how it went.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, the dumb mistake everyone makes
&lt;/h2&gt;

&lt;p&gt;I knew the rough shape of the fix from somewhere in the back of my brain: boot a live USB, chroot in, fix it. So naturally, sitting at the &lt;code&gt;grub&amp;gt;&lt;/code&gt; prompt, I confidently typed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;grub&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mount /dev/sdXn /mnt
&lt;span class="go"&gt;error: can't find command `mount'.
&lt;/span&gt;&lt;span class="gp"&gt;grub&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;arch-chroot /mnt
&lt;span class="go"&gt;error: can't find command `arch-chroot'.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GRUB just stared at me. Turns out the GRUB shell is not Linux. It has its own tiny set of commands, and &lt;code&gt;mount&lt;/code&gt; and &lt;code&gt;arch-chroot&lt;/code&gt; are not among them. Those are things you run later, from an actual live environment. Lesson one: the blue prompt is not a terminal, stop treating it like one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the error actually means
&lt;/h2&gt;

&lt;p&gt;GRUB's whole job is to grab a kernel and its initramfs, load them into memory, and hand off. The error shows up when GRUB has a menu entry pointing at a kernel file, in my case &lt;code&gt;/boot/vmlinuz-linux-lts&lt;/code&gt;, but that file simply isn't there. Nothing to load means nothing to boot. Hence the passive-aggressive "you need to load the kernel first."&lt;/p&gt;

&lt;p&gt;So the real mystery is: where did my kernel go?&lt;/p&gt;

&lt;h2&gt;
  
  
  Poking around from the GRUB shell
&lt;/h2&gt;

&lt;p&gt;Before doing anything drastic you can actually snoop on your disks from &lt;code&gt;grub&amp;gt;&lt;/code&gt;. List partitions with:&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;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I got back something like &lt;code&gt;(hd0,gpt5) (hd0,gpt4) (hd0,gpt3) (hd0,gpt2) (hd0,gpt1)&lt;/code&gt;. Then you just go fishing through them:&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;ls&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;hd0,gpt5&lt;span class="o"&gt;)&lt;/span&gt;/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The one that spits out &lt;code&gt;boot/ etc/ home/ usr/ var/ ...&lt;/code&gt; is your Linux root. Mine was gpt5. Then the moment of truth:&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;ls&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;hd0,gpt5&lt;span class="o"&gt;)&lt;/span&gt;/boot/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And &lt;code&gt;/boot&lt;/code&gt; contained... &lt;code&gt;amd-ucode.img&lt;/code&gt; and &lt;code&gt;grub/&lt;/code&gt;. That's it. No &lt;code&gt;vmlinuz-linux&lt;/code&gt;. No &lt;code&gt;initramfs-linux.img&lt;/code&gt;. My kernel had ghosted me. (Also, if you see an empty &lt;code&gt;boot/efi&lt;/code&gt; folder here, relax, that's just an unmounted mountpoint, not the problem.)&lt;/p&gt;

&lt;p&gt;At this point I genuinely considered just wiping the whole thing and starting fresh with some calmer distro. Do not do this. I'll get to why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the rescue USB without a second computer
&lt;/h2&gt;

&lt;p&gt;I only have the one laptop, which felt like a dealbreaker until I remembered it dual-boots Windows, and the Windows install was sitting there completely untouched on its own partition. So I booted into Windows straight from the BIOS boot menu (mash F12 / F2 / Esc at power-on depending on your machine), downloaded the EndeavourOS ISO, and flashed it to a USB stick with Rufus.&lt;/p&gt;

&lt;p&gt;If you run EndeavourOS, grab the EndeavourOS ISO. Vanilla Arch, grab the Arch ISO. Matching your actual distro saves you keyring headaches later.&lt;/p&gt;

&lt;h2&gt;
  
  
  The live USB also tried to ruin my day
&lt;/h2&gt;

&lt;p&gt;Booted the USB, picked the friendly default entry ("open source drivers, all GPUs"), and watched the screen blink at me forever. Black, blink, black, blink, nothing. This is apparently a beloved tradition on laptops with NVIDIA graphics: the normal graphical boot just refuses to come up.&lt;/p&gt;

&lt;p&gt;The fix is the entry nobody reads: &lt;strong&gt;fallback / nomodeset&lt;/strong&gt;. Reboot the USB, pick that, and it boots ugly but functional. That got me to a desktop. If you're stuck blinking, that's your move.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally, the actual repair
&lt;/h2&gt;

&lt;p&gt;Opened a terminal and ran the one command that changes nothing and tells you everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lsblk &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows your partitions and their filesystems. I was looking for two things: my root partition (ext4, helpfully labeled &lt;code&gt;endeavouros&lt;/code&gt;) and my EFI partition (small, FAT32). Mine were &lt;code&gt;nvme0n1p5&lt;/code&gt; and &lt;code&gt;nvme0n1p1&lt;/code&gt;. Yours might be &lt;code&gt;sda5&lt;/code&gt; / &lt;code&gt;sda1&lt;/code&gt; on an older SATA drive. Use your real names, not mine.&lt;/p&gt;

&lt;p&gt;Then mount everything and jump in:&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;mount /dev/nvme0n1p5 /mnt
&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /mnt/boot/efi
&lt;span class="nb"&gt;sudo &lt;/span&gt;mount /dev/nvme0n1p1 /mnt/boot/efi
&lt;span class="nb"&gt;sudo &lt;/span&gt;arch-chroot /mnt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the prompt flips to something like &lt;code&gt;[root@EndeavourOS /]#&lt;/code&gt;, you're now living inside your installed system instead of the USB. This is where the real commands work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The plot twist
&lt;/h2&gt;

&lt;p&gt;I figured I'd just reinstall the kernel and go to bed. But first I checked what was actually installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pacman &lt;span class="nt"&gt;-Q&lt;/span&gt; linux linux-lts mkinitcpio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And got this beautiful nonsense:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;linux 7.0.12.arch1-1
linux-lts 6.18.36-1
error: package 'mkinitcpio' was not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There it was. According to pacman, both kernels were perfectly installed. But &lt;code&gt;mkinitcpio&lt;/code&gt; was gone. And &lt;code&gt;mkinitcpio&lt;/code&gt; is the thing that actually builds your initramfs and gets the kernel images written into &lt;code&gt;/boot&lt;/code&gt; during install. No &lt;code&gt;mkinitcpio&lt;/code&gt; means the kernel package "installs" but never produces the files GRUB needs. The database lies to your face while &lt;code&gt;/boot&lt;/code&gt; sits there empty.&lt;/p&gt;

&lt;p&gt;How does &lt;code&gt;mkinitcpio&lt;/code&gt; go missing? Usually an upgrade that got interrupted, a &lt;code&gt;/boot&lt;/code&gt; that filled up mid-write, or a cleanup / package removal that took more than you meant it to. I genuinely don't remember which crime I committed, but the result was the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix that finally worked
&lt;/h2&gt;

&lt;p&gt;Install the missing piece, then reinstall the kernels so the hooks actually fire this time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pacman &lt;span class="nt"&gt;-S&lt;/span&gt; mkinitcpio
pacman &lt;span class="nt"&gt;-S&lt;/span&gt; linux linux-lts amd-ucode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Say yes to the reinstall. (I'm on AMD, hence &lt;code&gt;amd-ucode&lt;/code&gt;. Intel folks want &lt;code&gt;intel-ucode&lt;/code&gt;. Don't want the LTS kernel? Drop &lt;code&gt;linux-lts&lt;/code&gt; and the dead menu entry disappears on its own.)&lt;/p&gt;

&lt;p&gt;If pacman starts whining about keyrings or signatures, refresh them first with &lt;code&gt;pacman -Sy archlinux-keyring&lt;/code&gt; (add &lt;code&gt;endeavouros-keyring&lt;/code&gt; on EndeavourOS) and try again.&lt;/p&gt;

&lt;p&gt;Then check that the files actually showed up this time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; /boot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, the good stuff:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vmlinuz-linux                     vmlinuz-linux-lts
initramfs-linux.img               initramfs-linux-lts.img
initramfs-linux-fallback.img      initramfs-linux-lts-fallback.img
amd-ucode.img                     grub/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A populated &lt;code&gt;/boot&lt;/code&gt;. Chef's kiss. The kernels exist again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping it up
&lt;/h2&gt;

&lt;p&gt;Tell GRUB about its newly recovered kernels, then get out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;grub-mkconfig &lt;span class="nt"&gt;-o&lt;/span&gt; /boot/grub/grub.cfg
&lt;span class="nb"&gt;exit
sudo &lt;/span&gt;umount &lt;span class="nt"&gt;-R&lt;/span&gt; /mnt
reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pull the USB on the way down. It booted straight into my normal GRUB menu and into a working desktop like nothing had happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  While you're in there, two quick checks
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;df -h /boot&lt;/code&gt; and make sure it isn't basically full, because a stuffed &lt;code&gt;/boot&lt;/code&gt; is a great way to cause this exact mess again. And if you're paranoid, &lt;code&gt;mkinitcpio -P&lt;/code&gt; rebuilds every initramfs by hand, though the kernel reinstall already does it for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stuff I'd tell past me
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;grub&amp;gt;&lt;/code&gt; prompt is not bash. Stop typing Linux commands into it.&lt;/li&gt;
&lt;li&gt;Don't yank the power during a &lt;code&gt;pacman -Syu&lt;/code&gt;. Let kernel upgrades finish, especially on a laptop.&lt;/li&gt;
&lt;li&gt;Keep an eye on &lt;code&gt;/boot&lt;/code&gt; free space.&lt;/li&gt;
&lt;li&gt;Read what pacman is about to remove before hitting yes. If it wants to take &lt;code&gt;linux&lt;/code&gt; or &lt;code&gt;mkinitcpio&lt;/code&gt; with it, that's your sign to stop.&lt;/li&gt;
&lt;li&gt;Keep a flashed live USB in a drawer. It turns "my laptop is bricked" into "ugh, fifteen minutes."&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  And please don't just reinstall
&lt;/h2&gt;

&lt;p&gt;I almost did. It feels clean when you're frustrated. But reinstalling throws away all your config, takes way longer than the repair, and worst of all, fiddling with partitions next to a Windows install is a fantastic way to accidentally delete Windows too. The repair touches exactly two things: the kernel files and the GRUB config. The reinstall touches your entire disk. You need the same USB stick either way, so just try the repair first.&lt;/p&gt;

&lt;p&gt;My system, my dotfiles, my Windows install, all completely fine the whole time. I was just missing a couple of files and one very important package. That's it.&lt;/p&gt;

</description>
      <category>archlinux</category>
      <category>endeavouros</category>
      <category>troubleshooting</category>
    </item>
    <item>
      <title>I Forgot My Linux Password — And Reset It in 5 Minutes</title>
      <dc:creator>Seamoon Pandey</dc:creator>
      <pubDate>Tue, 09 Jun 2026 21:55:31 +0000</pubDate>
      <link>https://dev.to/seamoonpandey/i-forgot-my-linux-password-and-reset-it-in-5-minutes-2adj</link>
      <guid>https://dev.to/seamoonpandey/i-forgot-my-linux-password-and-reset-it-in-5-minutes-2adj</guid>
      <description>&lt;p&gt;Most Linux users assume their login password is the primary barrier protecting their system. Then one day they forget it.&lt;/p&gt;

&lt;p&gt;The surprising part? On many Linux distributions, resetting a forgotten password is remarkably easy if you have physical access to the machine.&lt;/p&gt;

&lt;p&gt;This isn't a vulnerability. It's a fundamental aspect of how local system administration works on Linux.&lt;/p&gt;

&lt;p&gt;Let's explore why password recovery works, how it's done, and what it teaches us about Linux security.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Situation
&lt;/h2&gt;

&lt;p&gt;Imagine you've been away from your laptop for a few weeks.&lt;/p&gt;

&lt;p&gt;You boot into your favorite Linux distribution, confidently type what you think is your password, and get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Authentication failure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You try again.&lt;/p&gt;

&lt;p&gt;Still wrong.&lt;/p&gt;

&lt;p&gt;A few more attempts later, you realize you've forgotten your password.&lt;/p&gt;

&lt;p&gt;Many people panic at this point, assuming they need to reinstall the operating system. Fortunately, that's rarely necessary.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Password Recovery Is Possible
&lt;/h2&gt;

&lt;p&gt;Linux separates several security concepts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User account passwords&lt;/li&gt;
&lt;li&gt;Root (administrator) privileges&lt;/li&gt;
&lt;li&gt;Physical access to the machine&lt;/li&gt;
&lt;li&gt;Disk encryption&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If someone can boot the operating system and obtain a root shell, they can change any user's password.&lt;/p&gt;

&lt;p&gt;The key insight is that Linux trusts administrators to manage user accounts.&lt;/p&gt;

&lt;p&gt;When you boot into recovery mode, you're effectively entering a maintenance environment where administrative actions are allowed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recovery Mode on Ubuntu-Based Distributions
&lt;/h2&gt;

&lt;p&gt;On distributions such as Ubuntu, Lubuntu, Kubuntu, Xubuntu, and Linux Mint, the process is straightforward.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Access GRUB
&lt;/h3&gt;

&lt;p&gt;During boot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hold &lt;code&gt;Shift&lt;/code&gt; on BIOS systems&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;Esc&lt;/code&gt; repeatedly on UEFI systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This should display the GRUB menu.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Enter Recovery Mode
&lt;/h3&gt;

&lt;p&gt;Navigate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Advanced options for Ubuntu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then select:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(recovery mode)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Open a Root Shell
&lt;/h3&gt;

&lt;p&gt;Choose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root - Drop to root shell prompt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now have administrative access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Remount the Filesystem
&lt;/h3&gt;

&lt;p&gt;The root filesystem is usually mounted read-only.&lt;/p&gt;

&lt;p&gt;Remount it as writable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mount &lt;span class="nt"&gt;-o&lt;/span&gt; remount,rw /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Reset the Password
&lt;/h3&gt;

&lt;p&gt;First, identify the username if necessary:&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;ls&lt;/span&gt; /home
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then change the password:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;passwd username
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;passwd john
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter a new password twice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Reboot
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You're done.&lt;/p&gt;




&lt;h2&gt;
  
  
  What About Other Linux Distributions?
&lt;/h2&gt;

&lt;p&gt;The same principle applies across most Linux systems.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Distribution&lt;/th&gt;
&lt;th&gt;Typical Recovery Method&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ubuntu Family&lt;/td&gt;
&lt;td&gt;Recovery Mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debian&lt;/td&gt;
&lt;td&gt;Single User Mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fedora&lt;/td&gt;
&lt;td&gt;Emergency Mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Arch Linux&lt;/td&gt;
&lt;td&gt;Recovery Shell or Live USB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EndeavourOS&lt;/td&gt;
&lt;td&gt;Same as Arch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;openSUSE&lt;/td&gt;
&lt;td&gt;Rescue Mode&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The interface differs, but the idea remains identical:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Obtain root access&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;passwd&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Set a new password&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Security Lesson
&lt;/h2&gt;

&lt;p&gt;Many new Linux users assume:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If someone doesn't know my password, they can't access my computer."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's only partially true.&lt;/p&gt;

&lt;p&gt;If an attacker has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Physical access&lt;/li&gt;
&lt;li&gt;The ability to boot the system&lt;/li&gt;
&lt;li&gt;An unencrypted drive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then they can often reset passwords without knowing the original one.&lt;/p&gt;

&lt;p&gt;This is expected behavior, not a bug.&lt;/p&gt;




&lt;h2&gt;
  
  
  Full-Disk Encryption Changes Everything
&lt;/h2&gt;

&lt;p&gt;Now consider a system protected by LUKS full-disk encryption.&lt;/p&gt;

&lt;p&gt;Before Linux even starts booting, you'll see something similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Please unlock disk...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without the encryption passphrase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recovery mode is inaccessible&lt;/li&gt;
&lt;li&gt;User data remains unreadable&lt;/li&gt;
&lt;li&gt;Password reset procedures become ineffective&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why security professionals often say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Your real protection isn't your login password—it's disk encryption.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The login password protects your account.&lt;/p&gt;

&lt;p&gt;Disk encryption protects your data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Linux Allows This
&lt;/h2&gt;

&lt;p&gt;At first glance, being able to reset passwords seems insecure.&lt;/p&gt;

&lt;p&gt;In reality, it solves a practical problem.&lt;/p&gt;

&lt;p&gt;System administrators occasionally forget passwords. Machines become inaccessible. Recovery tools are necessary.&lt;/p&gt;

&lt;p&gt;Linux follows a long-standing philosophy:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Physical access usually implies administrative control.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you want stronger protection against physical attacks, encryption—not account passwords—is the answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Resetting a forgotten Linux password is surprisingly simple across most distributions.&lt;/p&gt;

&lt;p&gt;The process demonstrates an important security principle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Passwords protect accounts.&lt;/li&gt;
&lt;li&gt;Root access controls the system.&lt;/li&gt;
&lt;li&gt;Physical access is powerful.&lt;/li&gt;
&lt;li&gt;Encryption protects data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The next time someone asks, "What happens if I forget my Linux password?" the answer is usually:&lt;/p&gt;

&lt;p&gt;"Boot into recovery mode, reset it, and carry on."&lt;/p&gt;

&lt;p&gt;The more interesting question is:&lt;/p&gt;

&lt;p&gt;"What protects the machine if someone else does the same thing?"&lt;/p&gt;

&lt;p&gt;The answer is full-disk encryption.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>ubuntu</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Apache Hadoop on Ubuntu 22.04 (Beginner-Friendly, Java 8 Without Breaking Java 21)</title>
      <dc:creator>Seamoon Pandey</dc:creator>
      <pubDate>Sat, 31 Jan 2026 14:43:23 +0000</pubDate>
      <link>https://dev.to/seamoonpandey/apache-hadoop-on-ubuntu-2204-beginner-friendly-java-8-without-breaking-java-21-1mb1</link>
      <guid>https://dev.to/seamoonpandey/apache-hadoop-on-ubuntu-2204-beginner-friendly-java-8-without-breaking-java-21-1mb1</guid>
      <description>&lt;p&gt;Hadoop is still a &lt;strong&gt;core concept&lt;/strong&gt; in data engineering — especially for understanding &lt;strong&gt;HDFS, YARN, and distributed systems&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The biggest blocker for beginners today is &lt;strong&gt;Java version conflicts&lt;/strong&gt;.&lt;br&gt;
Most modern systems run &lt;strong&gt;Java 17 or 21&lt;/strong&gt;, while Hadoop prefers &lt;strong&gt;Java 8&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This guide shows you how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Hadoop &lt;strong&gt;from scratch&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Java 8 only for Hadoop&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Keep your system Java untouched&lt;/li&gt;
&lt;li&gt;Avoid auto-start, battery drain, and common traps&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  What you’ll build
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Hadoop 3.3.6&lt;/li&gt;
&lt;li&gt;Single-node (pseudo-distributed)&lt;/li&gt;
&lt;li&gt;Ubuntu 22.04&lt;/li&gt;
&lt;li&gt;Java 8 for Hadoop only&lt;/li&gt;
&lt;li&gt;Manual start/stop (laptop-friendly)&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ubuntu 22.04&lt;/li&gt;
&lt;li&gt;Internet connection&lt;/li&gt;
&lt;li&gt;sudo access&lt;/li&gt;
&lt;li&gt;No prior Hadoop knowledge required&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Step 1: System preparation
&lt;/h2&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 update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ssh rsync curl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Hadoop relies on SSH — even on a single machine.&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 2: Create a dedicated Hadoop user (recommended)
&lt;/h2&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;adduser hadoop
&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;hadoop
su - hadoop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;From here on, &lt;strong&gt;everything runs as the &lt;code&gt;hadoop&lt;/code&gt; user&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 3: Enable passwordless SSH
&lt;/h2&gt;

&lt;p&gt;Hadoop services communicate over SSH.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_rsa.pub &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.ssh/authorized_keys
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 ~/.ssh/authorized_keys
ssh localhost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it logs in without asking for a password → you’re good.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Java setup (important)
&lt;/h2&gt;

&lt;p&gt;Hadoop works best with &lt;strong&gt;Java 8&lt;/strong&gt;.&lt;br&gt;
You &lt;strong&gt;do NOT&lt;/strong&gt; need to uninstall Java 17/21.&lt;/p&gt;

&lt;p&gt;Verify Java 8 exists:&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;ls&lt;/span&gt; /usr/lib/jvm/java-8-openjdk-amd64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it exists, continue.&lt;br&gt;
(You can install it with &lt;code&gt;sudo apt install openjdk-8-jdk&lt;/code&gt; if missing.)&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 5: Download Hadoop
&lt;/h2&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; ~
wget https://downloads.apache.org/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xvzf&lt;/span&gt; hadoop-3.3.6.tar.gz
&lt;span class="nb"&gt;mv &lt;/span&gt;hadoop-3.3.6 hadoop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Hadoop environment variables
&lt;/h2&gt;

&lt;p&gt;Edit &lt;code&gt;.bashrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add at the bottom:&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;export &lt;/span&gt;&lt;span class="nv"&gt;HADOOP_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/hadoop
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;HADOOP_INSTALL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HADOOP_HOME&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;HADOOP_MAPRED_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HADOOP_HOME&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;HADOOP_COMMON_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HADOOP_HOME&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;HADOOP_HDFS_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HADOOP_HOME&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;YARN_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HADOOP_HOME&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;:&lt;span class="nv"&gt;$HADOOP_HOME&lt;/span&gt;/bin:&lt;span class="nv"&gt;$HADOOP_HOME&lt;/span&gt;/sbin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply:&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;source&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 7: Bind Hadoop to Java 8 (critical step)
&lt;/h2&gt;

&lt;p&gt;This avoids breaking your other Java projects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano ~/hadoop/etc/hadoop/hadoop-env.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set:&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;export &lt;/span&gt;&lt;span class="nv"&gt;JAVA_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/lib/jvm/java-8-openjdk-amd64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hadoop version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Java version: 1.8.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 8: Hadoop configuration
&lt;/h2&gt;

&lt;p&gt;Move into config directory:&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;cd&lt;/span&gt; ~/hadoop/etc/hadoop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  core-site.xml
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;property&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;fs.defaultFS&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&lt;/span&gt;hdfs://localhost:9000&lt;span class="nt"&gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/property&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  hdfs-site.xml
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;property&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;dfs.replication&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/property&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;property&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;dfs.name.dir&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&lt;/span&gt;file:/home/hadoop/hadoopdata/namenode&lt;span class="nt"&gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/property&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;property&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;dfs.data.dir&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&lt;/span&gt;file:/home/hadoop/hadoopdata/datanode&lt;span class="nt"&gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/property&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create directories:&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;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/hadoopdata/namenode ~/hadoopdata/datanode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  mapred-site.xml
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp &lt;/span&gt;mapred-site.xml.template mapred-site.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;property&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;mapreduce.framework.name&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&lt;/span&gt;yarn&lt;span class="nt"&gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/property&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  yarn-site.xml
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;property&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;yarn.nodemanager.aux-services&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;value&amp;gt;&lt;/span&gt;mapreduce_shuffle&lt;span class="nt"&gt;&amp;lt;/value&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/property&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 9: Format the NameNode (run ONCE)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hdfs namenode &lt;span class="nt"&gt;-format&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ Running this again wipes HDFS metadata.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 10: Start Hadoop
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;start-dfs.sh
start-yarn.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected processes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NameNode&lt;/li&gt;
&lt;li&gt;DataNode&lt;/li&gt;
&lt;li&gt;SecondaryNameNode&lt;/li&gt;
&lt;li&gt;ResourceManager&lt;/li&gt;
&lt;li&gt;NodeManager&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 11: Access Web UIs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;HDFS: &lt;a href="http://localhost:9870" rel="noopener noreferrer"&gt;http://localhost:9870&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;YARN: &lt;a href="http://localhost:8088" rel="noopener noreferrer"&gt;http://localhost:8088&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If these load → Hadoop is running correctly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 12: Test HDFS
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hdfs dfs &lt;span class="nt"&gt;-mkdir&lt;/span&gt; /test
hdfs dfs &lt;span class="nt"&gt;-put&lt;/span&gt; ~/.bashrc /test
hdfs dfs &lt;span class="nt"&gt;-ls&lt;/span&gt; /test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Found 1 items
-rw-r--r-- 1 hadoop supergroup ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  About the “native-hadoop” warning
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WARN NativeCodeLoader: Unable to load native-hadoop library
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is &lt;strong&gt;normal&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hadoop falls back to pure Java&lt;/li&gt;
&lt;li&gt;No functionality is lost&lt;/li&gt;
&lt;li&gt;Safe to ignore for learning &amp;amp; development&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Does Hadoop auto-start on boot?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;No.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hadoop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does NOT register as a system service&lt;/li&gt;
&lt;li&gt;Does NOT start after reboot&lt;/li&gt;
&lt;li&gt;Uses &lt;strong&gt;zero resources&lt;/strong&gt; unless manually started&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To stop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;stop-dfs.sh
stop-yarn.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Viola you're done.&lt;/p&gt;

</description>
      <category>hadoop</category>
      <category>java</category>
      <category>programming</category>
    </item>
    <item>
      <title>Transferring SSH Keys (`id_rsa` and `id_rsa.pub`) to a New System</title>
      <dc:creator>Seamoon Pandey</dc:creator>
      <pubDate>Mon, 28 Oct 2024 08:51:54 +0000</pubDate>
      <link>https://dev.to/seamoonpandey/transferring-ssh-keys-idrsa-and-idrsapub-to-a-new-system-4knh</link>
      <guid>https://dev.to/seamoonpandey/transferring-ssh-keys-idrsa-and-idrsapub-to-a-new-system-4knh</guid>
      <description>&lt;p&gt;SSH keys are essential for secure communication between computers. If you're migrating to a new system but want to retain your existing SSH keys (&lt;code&gt;id_rsa&lt;/code&gt; and &lt;code&gt;id_rsa.pub&lt;/code&gt;), follow these steps to seamlessly transfer them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Locate Your SSH Keys
&lt;/h2&gt;

&lt;p&gt;First, identify the location of your SSH keys on your old system. Typically, they reside in the &lt;code&gt;~/.ssh/&lt;/code&gt; directory.&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;cd&lt;/span&gt; ~/.ssh/
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-al&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Backup Your Keys
&lt;/h2&gt;

&lt;p&gt;Ensure the safety of your SSH keys by creating a backup. Copy them to a secure location, such as an encrypted USB drive or a trusted cloud storage service.&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;cp &lt;/span&gt;id_rsa id_rsa.pub /path/to/backup/location
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Transfer the Keys to the New System
&lt;/h2&gt;

&lt;p&gt;Use the &lt;code&gt;scp&lt;/code&gt; (secure copy) command to transfer the SSH keys to your new system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;scp /path/to/backup/location/id_rsa /path/to/backup/location/id_rsa.pub user@new_system_ip:~/.ssh/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;user&lt;/code&gt; with your username on the new system and &lt;code&gt;new_system_ip&lt;/code&gt; with the IP address or hostname of your new system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Set Permissions
&lt;/h2&gt;

&lt;p&gt;Ensure that the permissions of your &lt;code&gt;id_rsa&lt;/code&gt; file are secure. Only the owner should have read and write permissions.&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;chmod &lt;/span&gt;600 ~/.ssh/id_rsa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Add Public Key to Authorized Keys
&lt;/h2&gt;

&lt;p&gt;Append the contents of your &lt;code&gt;id_rsa.pub&lt;/code&gt; file to the &lt;code&gt;authorized_keys&lt;/code&gt; file on your new system. This allows you to authenticate using your SSH private key.&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;cat&lt;/span&gt; ~/.ssh/id_rsa.pub &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Test the Connection
&lt;/h2&gt;

&lt;p&gt;Finally, test the SSH connection to your new system to ensure everything is set up correctly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh user@new_system_ip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If successful, you should log in to your new system without being prompted for a password.&lt;/p&gt;

&lt;p&gt;Congratulations! You've successfully transferred your SSH keys to your new system, ensuring secure access to your remote servers.&lt;/p&gt;




&lt;p&gt;Feel free to customize the instructions further based on your specific environment or requirements!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Reset password mailer implementation in rails 7 api, devise_token_auth, and sendgrid-ruby.</title>
      <dc:creator>Seamoon Pandey</dc:creator>
      <pubDate>Mon, 28 Oct 2024 08:45:37 +0000</pubDate>
      <link>https://dev.to/seamoonpandey/reset-password-mailer-implementation-in-rails-7-api-devisetokenauth-and-sendgrid-ruby-33mg</link>
      <guid>https://dev.to/seamoonpandey/reset-password-mailer-implementation-in-rails-7-api-devisetokenauth-and-sendgrid-ruby-33mg</guid>
      <description>&lt;p&gt;In this guide, we’ll walk through setting up password reset functionality in a Rails app using &lt;code&gt;devise_token_auth&lt;/code&gt; for authentication and SendGrid for email delivery. With this, users can request password reset links sent directly to their emails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependencies
&lt;/h2&gt;

&lt;p&gt;Add &lt;code&gt;devise_token_auth&lt;/code&gt; and &lt;code&gt;sendgrid-ruby&lt;/code&gt; to your &lt;code&gt;Gemfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Sendgrid for sending emails&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'sendgrid-ruby'&lt;/span&gt;

&lt;span class="c1"&gt;# Devise for authentication&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'devise_token_auth'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then install the dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or add each gem individually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle add &lt;span class="s1"&gt;'sendgrid-ruby'&lt;/span&gt;
bundle add &lt;span class="s1"&gt;'devise_token_auth'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;To generate Devise token auth files, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails g devise_token_auth:install User auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, open the generated migration file &lt;code&gt;...devise_token_auth_create_users.rb&lt;/code&gt;, and uncomment these lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;   &lt;span class="ss"&gt;:confirmation_token&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt; &lt;span class="ss"&gt;:confirmed_at&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt; &lt;span class="ss"&gt;:confirmation_sent_at&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;   &lt;span class="ss"&gt;:unconfirmed_email&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the migration:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;In your &lt;code&gt;user.rb&lt;/code&gt; model file, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;Devise&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Models&lt;/span&gt;
&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;DeviseTokenAuth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Concerns&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;

&lt;span class="c1"&gt;# Add :recoverable for password recovery&lt;/span&gt;
&lt;span class="n"&gt;devise&lt;/span&gt; &lt;span class="ss"&gt;:database_authenticatable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:registerable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:recoverable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;config/initializers/devise_token_auth.rb&lt;/code&gt;, configure password reset URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;change_headers_on_each_request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_password_reset_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'FRONTEND_URL'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/reset-password"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Routes Configuration
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;config/routes.rb&lt;/code&gt;, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;mount_devise_token_auth_for&lt;/span&gt; &lt;span class="s2"&gt;"User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;at: &lt;/span&gt;&lt;span class="s2"&gt;"auth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;controllers: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;passwords: &lt;/span&gt;&lt;span class="s2"&gt;"user/passwords"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Controller Setup
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;controllers/user/passwords_controller.rb&lt;/code&gt; for handling password reset actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# frozen_string_literal: true&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User::PasswordsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;DeviseTokenAuth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;PasswordsController&lt;/span&gt;
  &lt;span class="c1"&gt;# POST /auth/password&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resource_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:email&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;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;errors: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Email cannot be blank"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: :unprocessable_entity&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;resource_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_reset_password_instructions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s2"&gt;"If the email exists, password reset instructions have been sent."&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: :ok&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# PUT /auth/password&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;password_update_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:reset_password_token&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
      &lt;span class="n"&gt;authenticate_user!&lt;/span&gt;

      &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;valid_password?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password_update_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:old_password&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;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;errors: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Old password is incorrect"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: :unprocessable_entity&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="n"&gt;password_update_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s2"&gt;"Password updated successfully for authenticated user"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;errors: &lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;full_messages&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: :unprocessable_entity&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resource_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reset_password_by_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password_update_params&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;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s2"&gt;"If the email exists, password reset instructions have been sent."&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;errors: &lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;full_messages&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: :unprocessable_entity&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="n"&gt;password_update_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s2"&gt;"Password updated successfully"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;StandardError&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;errors: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"An unexpected error occurred: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: :internal_server_error&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;password_update_params&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:reset_password_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:password_confirmation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:old_password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;resource_params&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, users can initiate a password reset by sending a POST request to &lt;code&gt;/auth/password&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customizing the Email Template
&lt;/h2&gt;

&lt;p&gt;To modify the reset email, update &lt;code&gt;views/devise/mailer/reset_password_instructions.html.erb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="vi"&gt;@resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Someone requested a password reset. You can reset it via the link below.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="n"&gt;reset_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DeviseTokenAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_password_reset_url&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"?reset_password_token=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s1"&gt;'Change my password'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reset_url&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;If you didn’t request this, please ignore this email.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Your password won’t change until you create a new one.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Environment Setup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Sign in to &lt;a href="https://sendgrid.com/" rel="noopener noreferrer"&gt;SendGrid&lt;/a&gt;, set up your API key, and verify your sender email.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;dotenv&lt;/code&gt; or Rails credentials to securely store the following in your &lt;code&gt;.env&lt;/code&gt; file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SENDGRID_API_KEY=SG.******************
SENDER_EMAIL=your_verified_email@domain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Configure &lt;code&gt;SendGrid&lt;/code&gt; in your environment files (&lt;code&gt;config/environments/development.rb&lt;/code&gt; and &lt;code&gt;config/environments/production.rb&lt;/code&gt;):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action_mailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perform_deliveries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action_mailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;smtp_settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;address: &lt;/span&gt;&lt;span class="s2"&gt;"smtp.sendgrid.net"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;port: &lt;/span&gt;&lt;span class="mi"&gt;587&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;authentication: :plain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;user_name: &lt;/span&gt;&lt;span class="s2"&gt;"apikey"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# Keep as "apikey"&lt;/span&gt;
  &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"SENDGRID_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="ss"&gt;domain: &lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"BASE_URL"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="ss"&gt;enable_starttls_auto: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;And that’s it! Now, users can reset their passwords by requesting a link through your Rails API with Devise Token Auth and SendGrid.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devise-token-auth.gitbook.io/devise-token-auth/config" rel="noopener noreferrer"&gt;Devise Token Auth Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.twilio.com/docs/sendgrid/for-developers/sending-email/rubyonrails" rel="noopener noreferrer"&gt;SendGrid for Rails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/37692756/rails-devise-token-auth-gem-how-do-i-set-password-reset-link" rel="noopener noreferrer"&gt;Devise Password Reset on StackOverflow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>sendgrid</category>
      <category>devise</category>
      <category>rails</category>
      <category>forgotpassword</category>
    </item>
    <item>
      <title>Swapping Numbers Without a Temporary Variable in C using XOR like a pro.</title>
      <dc:creator>Seamoon Pandey</dc:creator>
      <pubDate>Thu, 22 Feb 2024 02:48:34 +0000</pubDate>
      <link>https://dev.to/seamoonpandey/swapping-numbers-without-a-temporary-variable-in-c-using-xor-like-a-pro-4jbp</link>
      <guid>https://dev.to/seamoonpandey/swapping-numbers-without-a-temporary-variable-in-c-using-xor-like-a-pro-4jbp</guid>
      <description>&lt;p&gt;Swapping the values of two variables without using a temporary variable is a classic programming problem. One elegant solution to this problem in C involves using bitwise XOR operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Algorithm
&lt;/h2&gt;

&lt;p&gt;Consider two variables &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;. The goal is to swap their values.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Initialize &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; with the values to be swapped.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Perform the following steps:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;^=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;^=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;^=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Explanation
&lt;/h2&gt;

&lt;p&gt;Let's break down the algorithm step by step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;a ^= b;&lt;/code&gt;: XOR (&lt;code&gt;^=&lt;/code&gt;) &lt;code&gt;a&lt;/code&gt; with &lt;code&gt;b&lt;/code&gt; and store the result back in &lt;code&gt;a&lt;/code&gt;. After this operation, &lt;code&gt;a&lt;/code&gt; contains the result of &lt;code&gt;a XOR b&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;b ^= a;&lt;/code&gt;: XOR &lt;code&gt;b&lt;/code&gt; with the new value of &lt;code&gt;a&lt;/code&gt; (which was the original value of &lt;code&gt;b&lt;/code&gt;). After this operation, &lt;code&gt;b&lt;/code&gt; contains the result of &lt;code&gt;b XOR (a XOR b)&lt;/code&gt;, which simplifies to &lt;code&gt;a&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;a ^= b;&lt;/code&gt;: XOR &lt;code&gt;a&lt;/code&gt; with the new value of &lt;code&gt;b&lt;/code&gt; (which was the original value of &lt;code&gt;a&lt;/code&gt;). After this operation, &lt;code&gt;a&lt;/code&gt; contains the result of &lt;code&gt;(a XOR b) XOR a&lt;/code&gt;, which simplifies to &lt;code&gt;b&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, &lt;code&gt;a&lt;/code&gt; holds the original value of &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; holds the original value of &lt;code&gt;a&lt;/code&gt;, effectively swapping their values without using a temporary variable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Consider the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;^=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;^=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;^=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>c</category>
      <category>swapping</category>
      <category>swap</category>
    </item>
    <item>
      <title>Ruby on Rails Api authentication with rails cookie session.</title>
      <dc:creator>Seamoon Pandey</dc:creator>
      <pubDate>Sun, 10 Dec 2023 03:55:45 +0000</pubDate>
      <link>https://dev.to/seamoonpandey/ruby-on-rails-api-authentication-with-rails-cookie-session-2jfi</link>
      <guid>https://dev.to/seamoonpandey/ruby-on-rails-api-authentication-with-rails-cookie-session-2jfi</guid>
      <description>&lt;h2&gt;
  
  
  Backend (Rails API)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Create a New Rails API Project
&lt;/h3&gt;

&lt;p&gt;To start building your Rails API, open your terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails new your_api_project_name &lt;span class="nt"&gt;--api&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; postgresql
&lt;span class="nb"&gt;cd &lt;/span&gt;your_api_project_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanation: This command initializes a new Rails API project, enabling API-only functionality and using PostgreSQL as the database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Integrate Devise and Devise Token Auth
&lt;/h3&gt;

&lt;p&gt;Add Devise and Devise Token Auth to your Gemfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'devise_token_auth'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, execute the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle &lt;span class="nb"&gt;install
&lt;/span&gt;rails generate devise:install
rails generate devise_token_auth:install
rails db:migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanation: These commands install and configure Devise along with Devise Token Auth. They set up authentication for your User model and create the necessary files and database tables.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Configure ApplicationController
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;app/controllers/application_controller.rb&lt;/code&gt;, add the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;API&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Cookies&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;DeviseTokenAuth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Concerns&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SetUserByToken&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanation: This configures your ApplicationController to include modules for handling cookies and setting the user based on the authentication token.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Configure Application
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;config/application.rb&lt;/code&gt;, add the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;api_only&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;session_store&lt;/span&gt; &lt;span class="ss"&gt;:cookie_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;key: &lt;/span&gt;&lt;span class="s1"&gt;'_your_api_session'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;httponly: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;same_site: :strict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;secure: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Cookies&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;session_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;session_options&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanation: These configurations ensure that your API works in an API-only mode, sets up secure cookie storage, and adds necessary middleware.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Configure Devise Token Auth
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;config/initializers/devise_token_auth.rb&lt;/code&gt;, add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cookie_enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cookie_attributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;httponly: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;encrypt: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;same_site: :strict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;secure: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;config/routes.rb&lt;/code&gt;, mount Devise Token Auth for the 'User' model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;mount_devise_token_auth_for&lt;/span&gt; &lt;span class="s1"&gt;'User'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;at: &lt;/span&gt;&lt;span class="s1"&gt;'auth'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanation: These configurations enable token authentication and set up cookie attributes for added security.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frontend (Using Axios)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 6: Set Up Axios for Authenticated Requests
&lt;/h3&gt;

&lt;p&gt;Install Axios using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add axios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when making authenticated requests, use Axios with &lt;code&gt;withCredentials: true&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your/api/endpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;withCredentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle the response&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle the error&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanation: Axios is a popular HTTP client for the browser and Node.js. The &lt;code&gt;withCredentials: true&lt;/code&gt; option ensures that cookies are sent with requests, crucial for authentication.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: Middleware for Authenticated Requests
&lt;/h3&gt;

&lt;p&gt;Consider creating a middleware for handling authentication in your frontend. Middleware can centralize logic for authenticated requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 8: Manage Authenticated State with a Cookie
&lt;/h3&gt;

&lt;p&gt;Use a &lt;code&gt;logged_in&lt;/code&gt; cookie to manage the authenticated state on the client side. Set it to &lt;code&gt;true&lt;/code&gt; on login and &lt;code&gt;false&lt;/code&gt; on logout or session expiration.&lt;/p&gt;

&lt;p&gt;Explanation: This helps keep track of the user's authentication status on the frontend, providing a seamless user experience.&lt;/p&gt;




&lt;p&gt;This guide covers the setup of a Rails API with token-based authentication using Devise and Devise Token Auth, along with frontend integration using Axios. Feel free to customize these steps based on your project's specific needs. If you have any questions or need further clarification, Mate, do some more research!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>cookie</category>
    </item>
  </channel>
</rss>
