Using cemerick/friend to protect ring/compojure routes and one gotcha

The friend clojure library is a great library providing a pluggable authentication and authorization “framework” (I know, frameworks are bad words these days) for protecting your clojure web application written using ring and/or compojure. We started using it to protect REST api calls from various sources (internal and external) and given that different clients may be using different authentication mechanisms (basic auth vs oauth) while still accessing the same endpoints, friend’s support for multiple workflows (think of these as authentication handlers) came to the rescue.

An example of multiple workflows setup is as follows:

(def secured-app
                 {:allow-anon? true
                  :unauthenticated-handler #(workflows/http-basic-deny "Friend demo" %)
                  :workflows [(workflows/http-basic
                                 :credential-fn #(creds/bcrypt-credential-fn @users %)
                                 :realm "Friend demo")
                              (workflows/my-auth-workflow :credential-fn #(mycred-fn %))]}))

That being said, there is a slight bug in the current friend library where the different workflows are run. Ideally, a request should be going through the workflows in a chain and only continue to the next workflow if the current one fails or returns nil. The relevant code uses the clojure map function which is optimized to not be lazy for items under 32. A pull request exists to fix this:

Once a request has been through the workflows and found the right one, the credential function/workflow returns an identity (e.g. username) and optionally some roles that can be used to authorize particular endpoints. One example is allowing read roles to access to GET endspoints but require write roles to create or update resources. As the role names are arbitrary, it is easy to use various conventions to generate and use them to isolate different actions on your REST server. In cases where you don’t need authorization by role, you can use some of the friend helper functions such as friend/authenticated.

One thing I’d like to see an example of would be principle based authorization rather than role based authorization. Given that a custom workflow can be written to emit an arbitrary set of “roles” which can be queried by the protected functions (it’s all injected into the request object), we can easily just change the compojure route to use friend/authenticated while each route handler then ensures that the correct role is present in the session to allow the user to go forward or not.

All in all, I’m pleased by the library and hope to use it more down the line.

– Sarwar Bhuiyan

Using cemerick/friend to protect ring/compojure routes and one gotcha

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s