How We Use Authorization as a UX Tool
Michel Oeler - Barcelona, Spain

How We Use Authorization as a UX Tool

Introduction

At some point in every application’s lifecycle you’ll come across the task of implementing an authorization framework. Choosing a framework is a hard enough task on its own, and there are great resources out there to help guide your choice. In this article we are going to focus on reimagining an authorization framework for developers as a UX tool for product teams.

We at Harled have used Pundit and Ruby on Rails for several initiatives which required complex authorization rules across our varied user base and we’ll base the rest of this article on those technologies. Pundit has enabled us to reach our security goal of authorization with explicit policies and scopes on our data with minimal setup and intuitive layout. However, focusing on the security aspect of the framework exposed some areas where user journeys and authorization dead ends collide.

Broken User Journeys In Authorization Frameworks

How They Happen

As our app scaled, so did our functionality, and by proxy — the number and complexity of our policies. The mismatch typically happens during the introduction of a new authorization rule that lacks consideration of UI elements which rely on it.

To illustrate, consider the example of the initial introduction of an authorization framework into a new application. You have a page with a list of users and each list element has show, edit and delete links (shoutout to the old reliable rails generators). You then receive a request to only show users other users of the same organization. You find your framework, then protect the user /show route with a policy:

Protecting a controller route with a Pundit Policy

Now if a user tries to access the profile of a user outside of their organization via direct link they will be redirected to the homepage. Done right? Well, not quite. This is where the UX piece comes into play. However, bookmarks aren’t a great way for users to access pages in your application. Users need links, lists and redirects for navigation. We’re missing a piece here to let the user know they can’t access the show page.

Fixing Broken Journeys

Let’s take a look at some strategies to help avoid dead-ends in your user journeys.

Using Policies In The UI

You most likely identified that we missed the step of wrapping the /show link in the .show? policy.

Connecting your UI to an authorization rule


This is a very useful method, but it does come with its drawbacks. We’ll talk about strategies and best practices when building the UI elements later in the article. For now, there’s a large question to be asked which leads to our next point:

What if the policy method contains logic which queries the database or puts load on your application?

In this scenario, we’ll run those queries on each iteration of the row resulting in increased load on your application. How do we get around it? Either reduce the logic in the policy check or switch to a policy scope.

Switch To A Policy Scope

Policies also expose conditional scoping for queries to keep data relevant to the user accessing it. Typically this is used when listing large amounts of data such as the above example to keep it to one query, instead of n queries.

Pundit policy scope example

Tracking

When a user identified a broken flow, we would address it almost immediately given the original size of our application. This was manageable for a while, but became unmaintainable with scale. We realized we needed a more robust way of tracking and prioritizing each flow, along with a confident, clear way to communicate them to our product team.

We started by hooking into Pundit’s framework and raising exceptions to the database whenever a user encountered a broken flow. To accomplish this, we leveraged a combination of the exception_notification gem and a custom setup for saving relevant state. We call these records: Pundit Exceptions.

Setting up Pundit to log database records when exceptions arise

The state saved in the exception is primarily comprised of

  • Time of day
  • Basic user Information
  • Request
  • Controller & Action
  • Query Parameters

I would like to take a moment to stress the importance of the query parameters. We have found many times that the query parameters play a key role in conducting a proper root cause analysis of why the flow is broken. They help determine the state of the application when the user hits the dead end. For example, the following routes look identical without the parameters included. However, with the parameters present we can identify that the user was conducting a search.

Reporting

When reporting on pundit exceptions we focus on one key metric: frequency.

A sudden increase in frequency helps to identify when a change failure was introduced. It’s a good idea to implement a post-deployment check which ensures there are no spikes in Pundit Exceptions following a change. But what if you’ve built a backlog of broken flows? The frequency of incoming Pundit Exceptions can help serve as an indicator of severity when prioritizing exceptions to tackle first. The more frequently the exception occurs, the more your users are trying to access the functionality, and the more they are getting frustrated!

Building A Dashboard

There’s an obstacle to overcome surrounding the communication of these exceptions to a non-technical team. We needed to find a way to enable (in our case) our product teams to identify and prioritize exceptions independently. To accomplish it, we built a dashboard to visualize the frequency of the exceptions in components. Below is a graph showing the number of Pundit Exceptions by controller action per day.

Graph to illustrate frequency of exceptions

We complement this with a table showing the top 10 exceptions in terms of occurrences and a quick view of the number of users affected in the last 24 hours (see below). The “Users affected in last 24 hours” metric is great for assessing the breadth of an issue. For example, a low number represents a potentially niche area of your application that doesn’t get much traffic.

Widgets to illustrate frequency of exceptions

Adding Context To The Dashboard With Ahoy

Ahoy is an analytics tool for ruby applications. We love it, and would strongly recommend it to anyone looking for an event analytics tool. One way we use ahoy is to augment a Pundit exception with a user journey for debugging. Even just the page before the exception hit will help with reproducibility.

A list of events illustrating how to augment an exception.

The cool thing here is it opens up the possibility for grouping problematic flows. From the above example we can see the user accessed the `users/:id/edit` route from the search. Remember how we talked about keeping query parameters in mind above? This is another great way to debug! In addition to debugging, it helps display the data in a way such that your product team can easily make educated decisions on redesigns or priority.

Avoiding Broken Flows During Development

We can all lean on 100% end-to-end test coverage to make sure there is never a pundit exception pushed again right? Wouldn’t that be nice… Well unfortunately we didn’t have that luxury, and quite frankly not many teams do! To avoid them, we had to follow a few simple rules when making authorization changes and building out our UI:

  • Make sure links and buttons are wrapped in their corresponding policy methods.
  • Encapsulate all logic in the policy. Combining a policy check with additional logic in the view (which is an anti-pattern in itself) is likely to lead to a broken flow. Think of the following, and how the button may be visible while the navigation will still fail.
Comparison of good and bad practices when making your UI responsive to your authorization rules
  • Align your policy scopes with their corresponding show methods. Instead of calling .show? on each record, use the policy scope to filter results to those the user is permitted to see. The trick here is to make sure your policy scope won’t include a record that will cause the show? method to fail.

Conclusion

Pundit is a great authorization tool, but if handled incorrectly it can cause headaches down the road. We talked a lot about identifying, tracking and reporting in this article but if there’s one main takeaway it’s that you always want your recurring Pundit Exceptions to be at zero. These dashboards can fit nicely in a post-deployment analysis or a housekeeping exercise if there are a lot of exceptions to fix. Figure out what makes the most sense for your application, and stay tuned for an open source project to help you accomplish everything in this article from Harled!

Who would have thought that 401s and 403s would be the main driver for a better UX! A really smart way to use Pundit and Ahoy for the benefit of end users. I can imagine, for a larger organization, the incredible opportunities to leverage this approach for proactive customer success activities.

To view or add a comment, sign in

Insights from the community

Others also viewed

Explore topics