Implementing Authentication in tiny steps
Tags: opensource, rails, webdev, programming
Published: 2022-08-04 13:07:00

When we started the project which we currently call "Arkency Ecommerce", under the RailsEventStore umbrella - it actually started as an Ordering Management System (OMS), more than actual ecommerce.

**I always thought that OMS is an obvious part of ecommerce platforms**. Recently I learnt it's not always the case, and even [Shopify recommend](https://www.shopify.com/enterprise/order-management-system-oms) looking at some other OMS systems as addition to their ecommerce.

Interesting.

Anyway, when our project grew, we were focused on the "Sales Panel" or "OMS panel". The user was probably a sales person. There was no authentication for that. We can assume that it's for internal use of the company hidden in the intranet.


![OMS view](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5351r83soqrq9o38uzea.png)

After some time, we have created the "Client View". At first it was without authentication too. We only added a "select list" to choose which client you are "logged in" as.


![login](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w1dr71rcdkgdatycnl0z.png)

However, even then, we just used the URL param to remember which client we're logged in as. Also, the functionality was and still is very limited. It was just a list of orders. 

There was also a detailed order view, but I just removed it. The reason I removed it, was because it didn't have tests and it didn't use its own read model, just borrowed from the OSM OrdersList read model. It doesn't sound like a big deal, but it actually is. We don't want changes to OSM to interfere with the Client Panel.

One of my recent changes was to extend the authentication with cookies storage, while still not having passwords yet.

I like the concept of tiny steps or as I like to call it "start from the middle".

We started without authentication, but we focused on how it would look like. After "seeing it"/"feeling it", we could decide what next.


![client panel](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9u9h1kq166c8lec2wltp.png)

That's the luxury of open source codebases, not limited to deadlines and clients. 

Small steps allow for two perspectives. 

**The code perspective**

We could start with some code hacks (coupling of read models) and buy some time to think how it should be reflected in the architecture. Only when we feel what smells we can come up with better architecture.
In this case, it was a realisation that the "client panel" is like a separate app. At the application layer it should be reflected in some way. I strongly believe in 2 levels of architectural split in typical web apps.
One level is app layer. The second one is domain layer. 

Often people confuse those two and try to merge them. Whatever is the app split, becomes the domain split. This is unfortunate as it's almost not possible to do such one-dimension split.

**The UI perspective**

Playing with the UI allows to rethink where we are with the features and what are the next stories to implement. Using the UI opens me in thinking what are the next tiny steps to add. 
Note that the authentication is not the most important feature of this area. It's crucial once we go live, but before that we can hide it behind a feature flag if we want. We all know how to build authentication. It's not the risky area. But we don't know what to put in the Client Panel exactly for it to be usable. This is more risky. 

**The current codebase**

```ruby
module Client
  class ClientsController < ApplicationController
    layout "client_panel"

    def index
      @clients = ClientOrders::Client.all
      render "clients/index"
    end

    def login
      cookies[:client_id] = params[:client_id]
      redirect_to client_orders_path
    end

    def logout
      cookies.delete(:client_id)
      redirect_to clients_path
    end
  end
end
```

```ruby
module Client
  class OrdersController < ApplicationController

    layout 'client_panel'

    def index
      render html: ClientOrders::OrdersList.build(view_context, cookies[:client_id]), layout: true
    end

  end
end

```

As you see, it's only setting the cookies, without any user/password checks.

This will be next story to implement, to allow for using passwords for logging in. What's interesting in this "tiny steps" approach is that we can start without even allowing for choosing the password. From the users perspective we can start with the idea of generating the passwords for the client, creating their accounts and only then (later) allowing them to choose/change passwords. That's like 3 other "stories" to implement.

As for the code, some of you may find this bit interesting:

```ruby
render html: ClientOrders::OrdersList.build(view_context, cookies[:client_id]), layout: true
```

I went for the Rails view implementation with an unusual approach - writing the templated in Ruby instead of ERB. 

But that's a topic for another blogpost.

Thanks!