Jekyll2023-12-01T10:33:38+00:00/feed.xmlWaiting for dev…I happen to be one of the roughly 106,000,000,000 human beings who have inhabited the Earth at some point. In this thing called society, I have taken on the role of a software developer. If I can assist you with anything or if you'd like to chat, please feel free to reach out to me.Open Source Status: November 2023 - dry-operation failure hooks & database transactions2023-12-01T00:00:00+00:002023-12-01T00:00:00+00:00/blog/2023/12/01/open_source_status_november_2023<p>This month, there’s a lot in the making! My two main priorities remain <a href="https://github.com/dry-rb/dry-operation">dry-operation</a> and <a href="https://github.com/waiting-for-dev/web_pipe">web_pipe</a>, and I’ve put a great deal of thought into both of them. I’m excited to share the progress I’ve made, so let’s get started!</p>
<h2 id="dry-operation-the-unhappy-path--database-transactions">dry-operation: the “unhappy” path & database transactions</h2>
<p>As I’ve discussed in <a href="/blog/2023/11/07/open_source_status_october_2023">previous updates</a>, dry-operation is all about streamlining the happy path. This doesn’t mean that the “unhappy” path is neglected, but it doesn’t impede understanding the intended flow. Usually, individual operations are responsible for locally managing their failures. Often, that’s sufficient. The caller will likely also perform some form of failure handling in respect to the entire flow, such as returning a 4xx response code. However, sometimes it’s useful to encapsulate part of that global error handling in the flow instance, treating it as something intrinsic that should be done regardless of the caller (e.g., logging a failure). To facilitate this, <a href="https://github.com/dry-rb/dry-operation/pull/14">we’re introducing an <code class="language-plaintext highlighter-rouge">#on_failure hook</code></a> that can be defined to be called when things go wrong.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">CreateUser</span> <span class="o"><</span> <span class="no">Dry</span><span class="o">::</span><span class="no">Operation</span>
<span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="n">input</span><span class="p">)</span>
<span class="n">attrs</span> <span class="o">=</span> <span class="n">step</span> <span class="n">validate</span><span class="p">(</span><span class="n">input</span><span class="p">)</span>
<span class="n">step</span> <span class="n">persist</span><span class="p">(</span><span class="n">attrs</span><span class="p">)</span>
<span class="n">user</span>
<span class="k">end</span>
<span class="kp">private</span>
<span class="k">def</span> <span class="nf">on_failure</span><span class="p">(</span><span class="n">failure</span><span class="p">)</span>
<span class="n">log_failure</span><span class="p">(</span><span class="n">failure</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1"># ...</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Regarding database transactions, there are two main approaches we could consider. The first is to wrap the entire flow in a transaction, which appears to be the more user-friendly option. The second is to require manually wrapping the desired operations via a <code class="language-plaintext highlighter-rouge">#transaction</code> method, allowing more fine-grained control. The general behavior in both cases would be the same: rolling back a DB transaction, if present, in the case of an operation returning a failure. After much consideration, we’ve decided to go with the second approach. A lot has been done to hide the impedance of database transactions from the developer’s eyes, and few of these efforts have been successful. Database transactions are lower-level details that developers need to be aware of, ensuring that no expensive operations are wrapped within them. Although it goes against a vision of composable flows, dry-operation will lean towards encouraging developers to compose operations instead of entire flows. Thanks to its design and helper libraries like dry-auto_inject, dry-operation operations are completely decoupled from the wrapping flow, making them suitable for composability at the right level of granularity.</p>
<p>An <a href="https://github.com/dry-rb/dry-operation/pull/15">extension for ROM</a> is the first working example of this approach, but we’d eventually add support for other libraries.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">MyOperation</span> <span class="o"><</span> <span class="no">Dry</span><span class="o">::</span><span class="no">Operation</span>
<span class="kp">include</span> <span class="no">Dry</span><span class="o">::</span><span class="no">Operation</span><span class="o">::</span><span class="no">Extensions</span><span class="o">::</span><span class="no">ROM</span>
<span class="nb">attr_reader</span> <span class="ss">:rom</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">rom</span><span class="p">:)</span>
<span class="vi">@rom</span> <span class="o">=</span> <span class="n">rom</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="n">input</span><span class="p">)</span>
<span class="n">attrs</span> <span class="o">=</span> <span class="n">step</span> <span class="n">validate</span><span class="p">(</span><span class="n">input</span><span class="p">)</span>
<span class="n">user</span> <span class="o">=</span> <span class="n">transaction</span> <span class="k">do</span>
<span class="n">new_user</span> <span class="o">=</span> <span class="n">step</span> <span class="n">persist</span><span class="p">(</span><span class="n">attrs</span><span class="p">)</span>
<span class="n">step</span> <span class="n">assign_initial_role</span><span class="p">(</span><span class="n">new_user</span><span class="p">)</span>
<span class="n">new_user</span>
<span class="k">end</span>
<span class="n">step</span> <span class="n">notify</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
<span class="n">user</span>
<span class="k">end</span>
<span class="c1"># ...</span>
<span class="k">end</span>
</code></pre></div></div>
<p>By the way, if you’re more interested in the thought process behind these decisions, you can check and comment on <a href="https://gist.github.com/waiting-for-dev/7615ae577807e3c3b990cd8c53670b2a">gist</a> where we discussed the approach to take.</p>
<h2 id="web_pipe-welcome-to-the-zeitwerk-family">web_pipe: welcome to the Zeitwerk family</h2>
<p>From now on, <a href="https://github.com/waiting-for-dev/web_pipe/pull/54">web_pipe is part of the growing family of Zeitwerk-enabled</a> Ruby gems.</p>
<p>Additionally, I’m experimenting a lot with its architecture, and it could result in a significant overhaul of its internals. The idea is to remove injection responsibilities from it and, instead, rely on something like dry-auto_inject. However, it’s still too soon to share more information, so please stay tuned!</p>This month, there’s a lot in the making! My two main priorities remain dry-operation and web_pipe, and I’ve put a great deal of thought into both of them. I’m excited to share the progress I’ve made, so let’s get started!Open Source Status: October 2023 - Syntax: dry-operation vs. do notation2023-11-07T00:00:00+00:002023-11-07T00:00:00+00:00/blog/2023/11/07/open_source_status_october_2023<p>In <a href="/blog/2023/10/10/open_source_status_september_2023">September</a>, we witnessed the birth of <a href="https://github.com/dry-rb/dry-operation">dry-operation</a>, a new library designed for managing business flows in Ruby. During October, my focus shifted towards optimizing its developer experience (DX) and also allowed me to revisit my beloved project, web_pipe.</p>
<h2 id="dry-operation-rubys-magic-wand-to-remove-boilerplate">dry-operation: Ruby’s magic wand to remove boilerplate</h2>
<p>I typically approach Ruby’s metaprogramming capabilities with caution. I’ve seen them misused too many times, and I strongly believe that, in most cases, being explicit rather than implicit is the better choice. However, there are certain scenarios where metaprogramming can be a powerful tool for reducing boilerplate and enhancing the developer experience. This is precisely where dry-operation shines.</p>
<p>The essence of dry-operation lies in crafting easily readable business flows, emphasizing the “happy path.” Back in September, we agreed upon the following interface:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">MyOperation</span> <span class="o"><</span> <span class="no">Dry</span><span class="o">::</span><span class="no">Operation</span>
<span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="n">input</span><span class="p">)</span>
<span class="n">steps</span> <span class="k">do</span>
<span class="n">attrs</span> <span class="o">=</span> <span class="n">step</span> <span class="n">validate</span><span class="p">(</span><span class="n">input</span><span class="p">)</span>
<span class="n">user</span> <span class="o">=</span> <span class="n">step</span> <span class="n">persist</span><span class="p">(</span><span class="n">attrs</span><span class="p">)</span>
<span class="n">step</span> <span class="n">notify</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
<span class="n">user</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">step</code> method will unwrap a <code class="language-plaintext highlighter-rouge">Dry::Monad::Result::Success</code> returned by each operation, but it’ll short-circuit the flow in case of <code class="language-plaintext highlighter-rouge">Failure</code>. It does so by throwing a symbol that is caught by the surrounding <code class="language-plaintext highlighter-rouge">#steps</code>.</p>
<p>Already, this is quite optimized for readability. Now, see how it could appear without dry-operation:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">MyOperation</span>
<span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="n">input</span><span class="p">)</span>
<span class="n">validate</span><span class="p">(</span><span class="n">input</span><span class="p">).</span><span class="nf">bind</span> <span class="k">do</span> <span class="o">|</span><span class="n">attrs</span><span class="o">|</span>
<span class="n">persist</span><span class="p">(</span><span class="n">attrs</span><span class="p">).</span><span class="nf">bind</span> <span class="k">do</span> <span class="o">|</span><span class="n">user</span><span class="o">|</span>
<span class="n">notify</span><span class="p">(</span><span class="n">user</span><span class="p">).</span><span class="nf">bind</span> <span class="k">do</span> <span class="o">|</span><span class="n">user</span><span class="o">|</span>
<span class="no">Success</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>You’re correct; we can do better with dry-monad’s do notation:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">MyOperation</span>
<span class="kp">include</span> <span class="no">Dry</span><span class="o">::</span><span class="no">Monads</span><span class="o">::</span><span class="no">Do</span><span class="p">.</span><span class="nf">for</span><span class="p">(</span><span class="ss">:call</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="n">input</span><span class="p">)</span>
<span class="n">attrs</span> <span class="o">=</span> <span class="k">yield</span> <span class="n">validate</span><span class="p">(</span><span class="n">params</span><span class="p">)</span>
<span class="n">user</span> <span class="o">=</span> <span class="k">yield</span> <span class="n">persist</span><span class="p">(</span><span class="n">attrs</span><span class="p">)</span>
<span class="k">yield</span> <span class="n">notify</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
<span class="no">Success</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>There are other benefits that dry-operation will provide over dry-monad’s do notation, but we can already compare their boilerplate. dry-operation comes out ahead in the following aspects:</p>
<ul>
<li>Inheriting from <code class="language-plaintext highlighter-rouge">Dry::Operation</code> is more concise than including <code class="language-plaintext highlighter-rouge">Dry::Monads::Do.for(:call)</code>.</li>
<li>Using a <code class="language-plaintext highlighter-rouge">step</code> method feels less confusing than <code class="language-plaintext highlighter-rouge">yield</code>.</li>
<li>There’s no need to explicitly wrap the returned value in a <code class="language-plaintext highlighter-rouge">Success</code> object in dry-operation.</li>
</ul>
<p>Nonetheless:</p>
<ul>
<li>dry-monad’s do notation doesn’t require wrapping the sequence of steps in a surrounding block (<code class="language-plaintext highlighter-rouge">steps</code> in dry-operation).</li>
</ul>
<p>Here’s where the metaprogramming magic comes into play. After a <a href="https://github.com/dry-rb/dry-operation/pull/11">couple</a> of <a href="https://github.com/dry-rb/dry-operation/pull/9">iterations</a>, and thanks to the valuable feedback from <a href="https://timriley.info/">Tim Riley</a>, the happy path in dry-operation has become even more straightforward, as the <code class="language-plaintext highlighter-rouge">#steps</code> block is no longer required:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">MyOperation</span> <span class="o"><</span> <span class="no">Dry</span><span class="o">::</span><span class="no">Operation</span>
<span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="n">input</span><span class="p">)</span>
<span class="n">attrs</span> <span class="o">=</span> <span class="n">step</span> <span class="n">validate</span><span class="p">(</span><span class="n">input</span><span class="p">)</span>
<span class="n">user</span> <span class="o">=</span> <span class="n">step</span> <span class="n">persist</span><span class="p">(</span><span class="n">attrs</span><span class="p">)</span>
<span class="n">step</span> <span class="n">notify</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
<span class="n">user</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>The way it works is that <code class="language-plaintext highlighter-rouge">Dry::Operation</code> will automatically prepend a <code class="language-plaintext highlighter-rouge">steps</code> block to the <code class="language-plaintext highlighter-rouge">#call</code> method. All batteries are included by default, but if you’re a purist there’s always the possibility to opt-out of any kind of magic through a <code class="language-plaintext highlighter-rouge">skip_prepending</code> class method.</p>
<h2 id="web_pipe-on-its-way-to-10">web_pipe: on it’s way to 1.0</h2>
<p><a href="https://github.com/waiting-for-dev/web_pipe">web_pipe</a> serves as a lightweight layer on top of Rack, designed for building composable web applications. It has been in existence for a while, yet it hasn’t reached version 1.0. I am committed to changing that and gradually solidifying its interface until the next major release. Last month, I made a few updates:</p>
<ul>
<li>I <a href="https://github.com/waiting-for-dev/web_pipe/pull/50">updated the hanami-view extension</a> to accommodate upstream breaking changes. It now can be used integrated within a Hanami 2.1 application.</li>
<li>I <a href="https://github.com/waiting-for-dev/web_pipe/pull/51">transitioned to GitHub actions</a> for CI, as it provides a better experience these days.</li>
<li>I also carried out some housekeeping tasks <a href="https://github.com/waiting-for-dev/web_pipe/pull/52">related to gem files</a> and adhered to some <a href="https://github.com/waiting-for-dev/web_pipe/pull/53">coding standards</a>.</li>
</ul>
<h2 id="whats-next">What’s next?</h2>
<p>In November, I anticipate dedicating my efforts to gracefully managing the “unhappy” path within dry-operation. Additionally, I’ll be exploring the optimal approach for integrating database transactions. I’m excited to make progress and continue moving forward!</p>In September, we witnessed the birth of dry-operation, a new library designed for managing business flows in Ruby. During October, my focus shifted towards optimizing its developer experience (DX) and also allowed me to revisit my beloved project, web_pipe.Open Source Status: September 2023 - Hello, dry-operation!2023-10-10T00:00:00+00:002023-10-10T00:00:00+00:00/blog/2023/10/10/open_source_status_september_2023<p>You promised yourself to provide monthly updates on your Open Source activities, and suddenly, a whole year has passed since the last one. But rest assured, I haven’t been idly lounging on the sofa during this time, as much as I might have wished for that luxury.</p>
<p>As I shared in my <a href="/blog/2022/10/02/open_source_status_september_2022">last update back in September 2022</a>, I’ve been dedicating a significant amount of thought to shaping a library for handling business transactions in Ruby. The spark was reignited when the possibility arose for this library to become an integral part of a service layer for <a href="https://solidus.io/">Solidus</a>. However, due to other pressing priorities within the project, my efforts were redirected, but I persevered, chipping away at it during my limited free time. Eventually, I successfully <a href="https://github.com/waiting-for-dev/kwork">developed a prototype</a>, which I affectionately named “kwork.” Naming can be quite a challenge. In this case, it paid homage to <a href="https://en.wikipedia.org/wiki/Murray_Gell-Mann">Murray Gell-Mann</a>, who originally contemplated the spelling “kwork” for <a href="https://en.wikipedia.org/wiki/Quark">quarks</a> (one of the fundamental constituents of matter). The pun tried to mirror the idea that business transactions, too, should be indivisible when it comes to their outputs:</p>
<blockquote>
<p>In 1963, when I assigned the name “quark” to the fundamental constituents of the nucleon, I had the sound first, without the spelling, which could have been “kwork”. Then, in one of my occasional perusals of Finnegans Wake, by James Joyce, I came across the word “quark” in the phrase “Three quarks for Muster Mark”.</p>
</blockquote>
<h2 id="kwork-is-no-more-long-live-dry-operation">Kwork is no more; long live dry-operation</h2>
<p>In Catalan, there’s a saying that goes, “Roda el món i torna al Born,” which loosely translates to “Travel the world and come back to El Born.” <a href="https://ca.wikipedia.org/wiki/El_Born">El Born</a> is an ancient district with medieval origins in Barcelona. My grandmother settled there with her family after fleeing their rural hometown, escaping the Francoist army, and it’s also where my mother was born. Today, it’s transformed into a hub of trendy shops, and the local community can no longer afford to reside there. Nevertheless, this saying conveys the notion that, after a multitude of new experiences, one often finds themselves back where they started. This sentiment beautifully encapsulates my journey with business transactions in Ruby.</p>
<p>Over four years ago, I submitted a <a href="https://github.com/dry-rb/dry-transaction/pull/119">PR to dry-transaction</a> to address one of its most significant limitations, which was the inability to freely reuse output from previous steps. Following discussions within the dry-rb team, Tim Riley informed me that they had decided to <a href="https://github.com/dry-rb/dry-transaction/pull/119#issuecomment-507005499">retire the library</a> due to this and other constraints. At that time, it was quite a disappointment for me, as I believed we were on the cusp of delivering exactly what Ruby needed: an idiomatic monadic DSL.</p>
<p>A couple of years later, now as a contributor to dry-rb, I proposed a couple of solutions to resurrect dry-transaction. The <a href="https://gist.github.com/waiting-for-dev/caece1891a84125fb3415026f8d310b3#file-dry_transaction_resurrection-rb">first approach</a> closely mirrored the old dry-transaction and the work in that PR, while <a href="https://gist.github.com/waiting-for-dev/caece1891a84125fb3415026f8d310b3#file-dry_transaction_resurrection2-rb">the second</a> leaned more towards the final shape of kwork or dry-monad’s do notation. However, the team was deeply engrossed in their work on Hanami, and it was entirely understandable that they couldn’t manage everything simultaneously.</p>
<p>Just last month, I learned that Tim Riley was eager to commence work on a dry-transaction successor. We engaged in extensive conversations over Slack, exchanging lengthy messages with Tim and Brooke Kuhlmann (author of <a href="https://alchemists.io/projects/transactable">transactable</a>). Concepts surrounding monads, do notation, dry-transaction, and the Railway Pattern were all in the mix, helping us to envisage what could potentially be the most fitting form for a Ruby library.</p>
<p>And so, here I am, actively contributing to the inception of <a href="https://github.com/dry-rb/dry-operation">dry-operation</a>. My initial work this month has involved the [extraction of key elements from kwork, molding them to align with the established patterns within the dry-rb ecosystem. I’m thrilled to report that we’ve already got the <a href="https://github.com/dry-rb/dry-operation/pull/6">syntax for the fundamental features</a> up and running, and we’re now diligently seeking the best possible <a href="https://github.com/dry-rb/dry-operation/pull/9">compromise to enhance the developer experience</a>.</p>
<p>On a personal note, I’ve been eagerly looking forward to deepening my collaboration with dry-rb for quite some time. Having the opportunity to spearhead the development of a new library fills me with immense joy and gratitude. I’d like to extend my heartfelt thanks to Tim and the entire team for placing their trust in me for this exciting endeavor!</p>You promised yourself to provide monthly updates on your Open Source activities, and suddenly, a whole year has passed since the last one. But rest assured, I haven’t been idly lounging on the sofa during this time, as much as I might have wished for that luxury.Open Source Status: September 20222022-10-02T00:00:00+00:002022-10-02T00:00:00+00:00/blog/2022/10/02/open_source_status_september_2022<p>This month was important in the personal sphere, as I moved out to the
mountains (well, in a town in the mountains, to be fair). Still, I managed to
dedicate some time to Open Source.</p>
<h2 id="decoupling-the-router-from-the-application">Decoupling the router from the application</h2>
<p>I already mentioned in the <a href="/blog/2022/09/01/open_source_status_august_2022">past update</a> that we were making hanami-router
an optional component in Hanami. I <a href="https://github.com/hanami/hanami/pull/1204">was working on a
PR</a>, but it needed to be reverted.
We were also trying to improve DX by raising an error when fetching the
configuration for a gem that is not there. We still need more work there, but
we extracted the part that makes hanami-router optional and merged it on
<a href="https://github.com/hanami/hanami/pull/1209">another PR</a>.</p>
<h2 id="in-the-freezer-taking-the-app-path-on-hanami-new">In the freezer: taking the app path on <code class="language-plaintext highlighter-rouge">hanami new</code></h2>
<p>I <a href="https://github.com/hanami/cli/pull/43">started this one</a> as a personal
initiative, as I really wanted to have <code class="language-plaintext highlighter-rouge">hanami new .</code> work. I always develop
using Docker, so my flow consists of initializing a container in the current
working directory where I want to create the application. One thing led to the
other, and I realized it was more natural to have the <code class="language-plaintext highlighter-rouge">hanami new</code> argument
always be a path instead of the app module name with <code class="language-plaintext highlighter-rouge">.</code> as an exception.
However, there’re some concerns about how it communicates to the user, and as
it’s not a priority at this point, we’ll retake it once more important stuff
has been done.</p>
<h2 id="in-progress-making-nested-slices-first-class">In progress: making nested slices first-class</h2>
<p>Tim introduced the option to <a href="https://github.com/hanami/hanami/pull/1162">register a slice within another
slice</a>. However, they’re not picked
for <em>slice configurable</em> things. We <a href="https://github.com/hanami/hanami/pull/1212">need to fix
it</a>.</p>
<h2 id="excited-with-a-layer-for-service-objects">Excited with a layer for service objects</h2>
<p>I <a href="/blog/2022/09/01/open_source_status_august_2022">already said</a> I
don’t talk about my work for Solidus here, as that’s part of my paid job, while
my OS Status is primarily something directed to my GitHub sponsorship.</p>
<p>However, I’m very excited about a service layer we’ll add there, as it will be
built taking concepts from monads, railway programming, and atomicity patterns.
That’s just the same idea I had for a new version of dry-transaction, so
there’s a total overlap in my mind. I don’t know where it will land, but I see
a field for collaboration here.</p>This month was important in the personal sphere, as I moved out to the mountains (well, in a town in the mountains, to be fair). Still, I managed to dedicate some time to Open Source.Open Source Status: August 20222022-09-01T00:00:00+00:002022-09-01T00:00:00+00:00/blog/2022/09/01/open_source_status_august_2022<p>Hey, there!</p>
<p>This month I decided to take the step and open <a href="https://github.com/sponsors/waiting-for-dev">sponsorship on
GitHub</a>. I reckon this entails
some kind of acknowledgment, so I’ll try to publish regular updates about my
Open Source status.</p>
<p>Let’s start with what happened last month (August 2022)!</p>
<p><strong>Important notice: I won’t report about what we’re doing at <a href="https://solidus.io/">Solidus</a>, as that’s
already part of my paid work with the fantastic team at
<a href="https://nebulab.com/">Nebulab</a>.</strong></p>
<h2 id="more-robust-application-detection-in-hanami">More robust application detection in Hanami</h2>
<p>We’ve improved how <a href="https://github.com/hanami/hanami/pull/1197">Hanami detects the application
file</a> to set up its environment.
Previously, it wasn’t possible to run <code class="language-plaintext highlighter-rouge">bundle exec hanami console</code> from a
sub-directory within the application root. Still, a bit of recursion up the
filesystem hierarchy improves the development experience <a href="https://github.com/hanami/cli/pull/34">at the command
line</a>. I initially took this one, and
<a href="https://timriley.info/">Tim</a>, who knows best how Hanami is organized, reshaped
it in the best possible way.</p>
<h2 id="listing-middlewares">Listing middlewares</h2>
<p>This one came from July, but the <a href="https://github.com/hanami/cli/pull/30">command to list all registered Rack
middlewares</a> got merged and included in
the latest beta of Hanami. The output is pretty informative, rendering the type
of the middleware (class, object…), the arguments provided on initialization,
and the path where it applies. It also required some <a href="https://github.com/hanami/hanami/pull/1191">minor adjustments in
Hanami</a>’s main repo.</p>
<h2 id="reloading-hanami-console">Reloading Hanami console</h2>
<p>We’ve introduced a <a href="https://github.com/hanami/cli/pull/36"><code class="language-plaintext highlighter-rouge">reload</code> method available in the Hanami
console</a>. Its implementation was no
secret; it was just copied from what Hanami 1 did: replacing the current
process with a new invocation.</p>
<h2 id="minor-improvements">Minor improvements</h2>
<p>We <a href="https://github.com/hanami/hanami/pull/1206">removed a leftover file</a> and
all <a href="https://github.com/hanami/hanami/pull/1207">the old integration tests</a>.
The latter will make the test suite less confusing for new developers.</p>
<h2 id="under-way-decoupling-the-router-from-the-application">Under way: decoupling the router from the application</h2>
<p>Hanami 2 is not only for web applications, so the router is not a mandatory
system part. We’re using the same logic already present for actions and views
to <a href="https://github.com/hanami/hanami/pull/1204">make router configuration
optional</a>. Following Tim’s
recommendations, we’ve also improved the developer experience with a clear
error message.</p>
<p>That’s pretty much everything. However, I don’t want to say goodbye without
thanking <a href="https://github.com/swilgosz">Seb</a> for being my first sponsor (and,
once more, for his amazing work at
<a href="https://hanamimastery.com/">HanamiMastery</a>).</p>
<p>See you soon!</p>Hey, there!A walk with JWT and security (and IV): A secure JWT authentication implementation for Rack and Rails2017-01-26T08:19:23+00:002017-01-26T08:19:23+00:00/blog/2017/01/26/a_secure_jwt_authentication_implementation_for_rack_and_rails<p>After having discussed in the three previous posts (<a href="/blog/2017/01/23/stand_up_for_jwt_revocation">I</a>, <a href="/blog/2017/01/24/jwt_revocation_strategies">II</a> and <a href="/blog/2017/01/25/jwt_secure_usage">III</a>) about JWT authentication and security, I would like to share two Ruby libraries I made in order to implement these security tips we have discussed so far. One of them is <a href="https://github.com/waiting-for-dev/warden-jwt_auth">warden-jwt_auth</a>, which can be used in any Rack application that uses <a href="https://github.com/hassox/warden">Warden</a> as authentication library. The other one is <a href="https://github.com/waiting-for-dev/devise-jwt">devise-jwt</a>, which is just a thin layer on top of the first that automatically configures for <a href="https://github.com/plataformatec/devise">devise</a> and, subsequently, for Ruby on Rails.</p>
<h2 id="what-did-i-expect-from-a-jwt-authentication-ruby-library">What did I expect from a JWT authentication Ruby library?</h2>
<p>When I looked for current Ruby libraries helping with JWT authentication, I wanted them to have a string of conditions:</p>
<ul>
<li>I wanted it to rely on Warden, a heavily tested authentication library that works for any kind of Rack application. This decision was also based on the fact that most applications in my current company use it.</li>
<li>It should be easily pluggable into Rails with Devise (which uses Warden). That way, in Rails applications, I could use Devise database authentication for the sign-in action and JWT for the rest.</li>
<li>Relying on Warden and not being a full authentication system, it should be very simple to audit.</li>
<li>Zero monkey patching. A lot of libraries meant to work with Devise have a lot of monkey patching. I don’t like that.</li>
<li>It should be ORM agnostic when used outside of Rails.</li>
<li>It should support or make easy the implementation of a revocation strategy on top of JWT.</li>
<li>It should be flexible enough to distinguish between different user resources (like a <code class="language-plaintext highlighter-rouge">User</code> and an <code class="language-plaintext highlighter-rouge">AdminUser</code>), so that a token valid for one of them can’t impersonate another resource user record.</li>
</ul>
<p>I looked at what it had been done so far, and here it is what I found.</p>
<ul>
<li>
<p><a href="https://github.com/nsarno/knock">Knock</a>. Surely, it is the most serious attempt of implementing JWT authentication for Rails applications. But it is Rails specific, <a href="https://github.com/nsarno/knock/issues/70">does not integrate with devise</a> and it has <a href="https://github.com/nsarno/knock/issues/15">ruled out adding a revocation layer</a>.</p>
</li>
<li>
<p><a href="https://github.com/eparreno/rack-jwt">rack-jwt</a> It is nice that it is for any Rack application, but it is also true that it needs some handwork to integrate with tested authentication libraries like Warden. Besides, it doesn’t help with revocation.</p>
</li>
<li>
<p><a href="https://github.com/brocoders/jwt_authentication">jwt_authentication</a> It is only for Rails with devise. I think is quite complex and tries to mix <a href="https://github.com/gonzalo-bulnes/simple_token_authentication">simple_token_authentication</a>, which adds even more complexity and monkey patching. It doesn’t support revocation.</p>
</li>
</ul>
<h2 id="what-i-have-done">What I have done</h2>
<p>As I said, finally I ended up programming two libraries. I’m not going to go through their details, because they can be consulted in their README and surely they will change over time. I’ll just give some generic vision of what they are.</p>
<h3 id="warden-jwt_auth">warden-jwt_auth</h3>
<p><a href="https://github.com/waiting-for-dev/warden-jwt_auth">warden-jwt_auth</a> works for any Rack application with Warden.</p>
<p>At its core, this library consists of:</p>
<ul>
<li>A Warden strategy that authenticates a user if a valid JWT token is present in the request headers.</li>
<li>A rack middleware which adds a JWT token to the response headers in configured requests.</li>
<li>A rack middleware which revokes JWT tokens in configured requests.</li>
</ul>
<p>As it requires the user to implement user resource interfaces along with revocation strategies, it is completely ORM agnostic.</p>
<p>Having warden the ‘scopes’ concept, they can be leveraged to flag each token in order not to confuse user records from different resources.</p>
<h3 id="devise-jwt">devise-jwt</h3>
<p><a href="https://github.com/waiting-for-dev/devise-jwt">devise-jwt</a> is just a thin layer on top of warden-jwt_auth. It configures it to be used out of the box for devise and rails.</p>
<p>Basically, it does:</p>
<ul>
<li>Creates a devise module, which when added to a user devise model configures it to be able to use the JWT authentication strategy. This devise module implements required user interface for ActiveRecord.</li>
<li>Implements some revocation strategies for ActiveRecord.</li>
<li>Configure create session devise requests to dispatch tokens.</li>
<li>Configure destroy session devise requests to revoke tokens.</li>
</ul>
<p>Hope they can be useful.</p>After having discussed in the three previous posts (I, II and III) about JWT authentication and security, I would like to share two Ruby libraries I made in order to implement these security tips we have discussed so far. One of them is warden-jwt_auth, which can be used in any Rack application that uses Warden as authentication library. The other one is devise-jwt, which is just a thin layer on top of the first that automatically configures for devise and, subsequently, for Ruby on Rails.A walk with JWT and security (III): JWT secure usage2017-01-25T08:43:41+00:002017-01-25T08:43:41+00:00/blog/2017/01/25/jwt_secure_usage<p>In this post, after having discussed the <a href="/blog/2017/01/23/stand_up_for_jwt_revocation">why</a> and <a href="/blog/2017/01/24/jwt_revocation_strategies">how</a> on revoking JWT tokens, we’ll talk about some general advice that should be kept in mind while using JWT for user authentication.</p>
<p>The most important one is what we have already mentioned: add a revocation layer on top of JWT, even if it implies losing its stateless nature. The opposite is, most of the time, not acceptable. But there are more aspects to consider.</p>
<ul>
<li>
<p>Don’t add information that may change for a user. For instance, many times people recommend adding role information so that a database query can be saved. For example, in your JWT payload, you would add that Alice has the user ID and the <code class="language-plaintext highlighter-rouge">admin</code> role. What happens if <code class="language-plaintext highlighter-rouge">admin</code> privilege is revoked for Alice? If the token that states the opposite is still valid, they could still appear as an <code class="language-plaintext highlighter-rouge">admin</code>.</p>
</li>
<li>
<p>Don’t add private information unless you encrypt your tokens. Bare JWT (without encryption) is just a signed token. It means that the server perfectly knows whether it issued the incoming token or not. But the information contained in the token is readable by everyone ([try it in the ‘Debugger’ section on <a href="https://jwt.io/">JWT site</a>); it is just base64 encoded. So I recommend just encoding harmless information like the user id.</p>
</li>
<li>
<p>Be careful about what you use to identify a user. For example, if you just add the user id and you have two different user resources, say a User and an AdminUser, a valid token for the User with id 3 would be valid for the AdminUser with the same id. In this case, you should add and use something like a scope claim to distinguish between the two.</p>
</li>
</ul>
<p>With all of that in mind, in my view, when choosing an authentication mechanism, if possible, you should prefer using cookies. They have been around for a long time and they are battle-tested. Authentication is an essential security aspect of an application, and the closer you stay to the standard way, the more peacefully you will sleep.</p>
<p>So, in which situations might it be better not to use cookies? I can think of two:</p>
<ul>
<li>
<p>It is not easy to share cookies between different domains. That’s not true for <a href="https://en.wikipedia.org/wiki/Cross-origin_resource_sharing">CORS</a> requests, where the Access-Control-Allow-Credentials header can be used to instruct the browser to accept them. But, for instance, routine GET requests exclude you from this option.</p>
</li>
<li>
<p>Mobile platform support. It is no longer an issue for acceptable modern APIs, but if you need legacy compatibility, you could encounter troubles.</p>
</li>
</ul>
<p>Besides, you should be aware that JWT authentication could expose you to <a href="https://en.wikipedia.org/wiki/Cross-site_scripting">XSS attacks</a>, even though it is also true that cookies could expose you to <a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery">CSRF</a> attacks. In both cases, the best thing you can do is use good and modern tools and frameworks, always avoiding reinventing the wheel.</p>In this post, after having discussed the why and how on revoking JWT tokens, we’ll talk about some general advice that should be kept in mind while using JWT for user authentication.A walk with JWT and security (II): JWT revocation strategies2017-01-24T06:20:17+00:002017-01-24T06:20:17+00:00/blog/2017/01/24/jwt_revocation_strategies<p>In <a href="/blog/2017/01/23/stand_up_for_jwt_revocation">my last post</a> I concluded why, in my view, JWT revocation makes a lot of sense. Now, it’s time to analyze which revocation strategies can be used and what their pros and cons are</p>
<h2 id="short-lived-tokens">Short-Lived tokens</h2>
<p>The first one I’ll mention is not an actual revocation strategy, but some people argue that it is the best you can do with JWT to maintain its stateless nature while still mitigating its lack of built-in revocation. They say JWT tokens should have short expiration times, like, say, 15 minutes. This way, the time frame for an attacker to do some harm is reduced.</p>
<p>I don’t agree with that. I think it is still unacceptable not to have an actual server-side sign-out request. Shouldn’t the client do the right job destroying the token, a user could think that she has signed out from a server, but somebody coming just after them could be able to impersonate them.</p>
<p>Furthermore, it also has implications from a usability point of view. In some sites, such as online banking, it makes sense to force a user to sign in again if he has been inactive for 15 minutes, but in other scenarios, it can be a real hassle.</p>
<h2 id="signing-key-modification">Signing Key Modification</h2>
<p>Changing the signing key automatically invalidates all issued tokens, but it is not a way to invalidate single tokens. Doing that in a sign-out request would mean that everybody gets kicked out when just one requires leaving. Changing the signing key is something that must be done when there is some indication that it could have been compromised, but it doesn’t fit the scenario we are talking about.</p>
<h2 id="tokens-denylist">Tokens Denylist</h2>
<p>Keeping a denylist of tokens is the simplest actual revocation strategy for individual tokens that can be implemented. If we want to invalidate a token, we extract from it something that uniquely identifies it, like its “jti” claim, and we store this information in somewhere (for example, a database table). Then, each time a valid token arrives, the same information is extracted from it and queried against the denylist to decide whether to accept or refuse the token.</p>
<p>It is very important to notice that what is persisted is not the whole token but some information that uniquely identifies it. Should we persist the whole token, we will do that using encryption and adding a different salt for each one of them, treating it similarly to a password. However, for example, a “jti” claim alone is completely useless for an attacker.</p>
<p>A denylist strategy has some advantages:</p>
<ul>
<li>
<p>Very easy to implement.</p>
</li>
<li>
<p>It works well when we can have a user signed in from different devices, and we just want to sign her out from one of them. Each denylist record references one single token, so we have complete control.</p>
</li>
</ul>
<p>But it also has some drawbacks:</p>
<ul>
<li>
<p>With a denylist, there would be no way to sign a user out from all their devices. We would need to add some flag in the user record.</p>
</li>
<li>
<p>A denylist can grow quite rapidly if the user base is large enough because, at least, every sign-out request would add a record. To mitigate it, maintenance cleaning could be scheduled, which would empty the list at the same time that the signing key is changed. Of course, this would sign out all users, but surely it is something we can live with.</p>
</li>
<li>
<p>A denylist usually requires a second query (the one to the list) besides the usually needed query for the user.</p>
</li>
</ul>
<h2 id="user-attached-token">User-Attached Token</h2>
<p>This strategy is analogous to what is usually done with opaque tokens. Here, the information that uniquely identifies a token is stored attached to the same user record that it authorizes; for example, as another column in the user record. When a token with a valid signature comes in, that information is extracted and compared with the one attached to the user to decide whether authorization should be allowed. When we want to sign out the token, we simply change or nullify it.</p>
<p>In fact, these two steps in the checking process (fetching the user and comparing the token with the persisted information) can be reduced to a single one if we fetch the user through the token information. For example, we could have a “uid” column where we would store the “jti” claim of the current active token. When fetching the user, we would look that column up, and no matching would mean that the token is not valid. Of course, we need to be sure that the “uid” is actually unique.</p>
<p>As in the case of the denylist strategy, it is very important to understand that it is not the whole token that is persisted but a unique representation of it to avoid security concerns related to secrets storage (see the denylist section for details).</p>
<p>User-attached tokens have several advantages that, for me, make it a better idea than the denylist strategy:</p>
<ul>
<li>
<p>Instead of storing which tokens are not valid (which grows over time), we store the one that is valid. As a consequence, there is no need to schedule any clean-up.</p>
</li>
<li>
<p>A single query to the user resource suffices to do the checking, instead of having to query both the user and a denylist.</p>
</li>
</ul>
<p>On the other side, it also has one inconvenience:</p>
<ul>
<li>It makes dealing with multiple client applications from which a single user can interact more challenging. In this scenario, in the user storage, we should differentiate active tokens per client application, maybe using different columns or doing some kind of serialization. From the token side, a good idea would be to differentiate the client through the “aud” claim. Signing out from one device would mean revoking just the affected token, while signing out from all clients would require revoking all the tokens for that user.</li>
</ul>In my last post I concluded why, in my view, JWT revocation makes a lot of sense. Now, it’s time to analyze which revocation strategies can be used and what their pros and cons areA walk with JWT and security (I): Stand up for JWT revocation2017-01-23T11:02:55+00:002017-01-23T11:02:55+00:00/blog/2017/01/23/stand_up_for_jwt_revocation<p>There is some debate about whether JWT tokens should be revoked, for example, when signing a user out, or whether doing so is nonsense and breaks the primary reason why this technology exists.</p>
<p>JWT tokens are self-describing. They encapsulate the information that a client is trying to provide to an API, such as the ID of a user trying to authenticate. For this reason, they are defined as stateless. The server only needs to validate that the incoming token has its own signature to trust it; it doesn’t have to query any other server, like a database or another API.</p>
<p>Self-describing tokens exist in opposition to more traditional opaque tokens, which are usually strings of characters that an API needs to check against another server to see if they match the one associated with a user record.</p>
<p>The stateless nature of a pure JWT implementation has a very important implication. A server has nothing to say about a token except whether it was signed by itself or not, so it has no way to revoke them individually (it could invalidate all issued tokens at once by changing its signing key, but not a single one in isolation). This means that it is not possible to create an actual sign-out request from the server-side.</p>
<p>Even though this fact can be seen as a testament to stateless purism, I consider it close to an abomination from a security point of view. It is true that if both the client and API belong to the same team, client-side token revocation can be kept under control. But server-side technologies have better tools to deal with security and fewer attack vectors, like, say, a web browser. If the API is consumed by third-party clients, then relying on the assumption that they will do the right job is completely unacceptable.</p>
<p>However, there is nothing in JWT technology that prevents adding a revocation layer on top of it. In this scenario, an incoming token is verified, and, like in opaque tokens, another server is reached to check if it is still valid.</p>
<p>At first glance, it actually seems like nonsense. It looks like we are ending up in the same land as opaque tokens with the additional signature verification overhead. However, a closer look reveals that we gain some security benefits and that, in fact, there is no such overhead.</p>
<p>Let’s first examine the security benefits we can get. When revoking a JWT token, there is no need to store the whole token in the database. As it contains readable information, we can, for example, extract its “jti” claim, which uniquely identifies it. This is a huge advantage because it means that the stored information is completely useless for an attacker. Therefore, there is no need to hash it to implement a good zero-knowledge policy, and there is no need to keep a salt value for each user to protect against rainbow table attacks.</p>
<p>Now, about the alleged overhead that JWT with revocation would entail. As we said, with JWT, we have to take two steps: signature verification and a server query. In opaque tokens, it seems like we only have to query the server. But that is not true. A secure opaque token implementation should not store unencrypted tokens. Instead, it should require the client to send a kind of user UID along with the unencrypted token. The user UID would be used to fetch the user, and the unencrypted token would be securely compared with the hashed one. So, this hash comparison is also a second step, which, even though I haven’t benchmarked it, should have a similar overhead to signature verification.</p>
<p>Using a standard like JWT also has some abstract benefits that are difficult to measure. For example, usually, with current libraries, you get integrated expiration management through the “exp” claim. However, as far as I know, there is no standard for opaque tokens, which makes libraries prone to reinvent the wheel every time. In general, using JWT should be more portable.</p>
<p>Of course, I’m not saying that JWT with revocation is always good and opaque tokens are always bad. There have been detected JWT-specific attacks that good libraries should have fixed, and irresponsible use of JWT can have some dangers that we’ll examine in further posts. In the end, developers must be aware of what they are using, and a secure opaque token implementation is also very valid. But adding the revocation layer on top of JWT shouldn’t be disregarded as easily. In the next post, we’ll take a look at some revocation strategies that can be implemented.</p>
<hr />
<p>Background on the debate about JWT security and revocation:</p>
<ul>
<li><a href="https://auth0.com/blog/cookies-vs-tokens-definitive-guide/">Cookies vs Tokens: The Definitive Guide</a></li>
<li><a href="http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/">Stop using JWT for sessions</a></li>
<li><a href="https://www.dinochiesa.net/?p=1388">I don’t see the point in Revoking or Blacklisting JWT</a></li>
</ul>There is some debate about whether JWT tokens should be revoked, for example, when signing a user out, or whether doing so is nonsense and breaks the primary reason why this technology exists.