Authentication and Authorization with Friend and Buddy

Learn how authentication and authorization fit into Ring applications, when Friend is mainly historical context, and why modular Buddy-style middleware remains a practical model for modern Clojure web apps.

Authentication: Verifying who a client is. Authorization: Deciding what that authenticated client is allowed to do.

In Clojure web applications, these concerns usually live at the Ring boundary. Friend is historically important in the ecosystem and still useful to understand, but many current codebases prefer more modular Buddy-style middleware and explicit route or handler-level authorization checks. The real design question is not which library name sounds better. It is how clearly the app separates identity, session or token handling, and permission policy.

Keep Authentication and Authorization Distinct

These two concerns often get blurred:

  • authentication answers “who is this?”
  • authorization answers “may they do this?”

A session cookie, bearer token, or JWT may establish identity, but the application still needs clear policy rules for what that identity can access.

Many security bugs come from treating authentication as if it were most of the work. In practice, identity establishment is only the first step. The harder part is making authorization rules visible, consistent, and reviewable.

Treat Identity as Boundary Data

One useful design habit is to attach authentication results to the request as boundary data, then let downstream code make explicit authorization decisions. That keeps the security model reviewable:

  • middleware establishes identity
  • handlers or services decide whether the action is allowed
  • denial behavior is explicit rather than hidden

This is also what keeps authorization from becoming route-by-route improvisation. If the request has explicit identity context, downstream code can apply policy deliberately instead of guessing which middleware already ran.

Friend Is Historical Context, Buddy Is a More Modular Baseline

Friend helped define a lot of Ring-oriented auth workflows, especially in older applications. Buddy-style libraries are usually easier to compose in more modern code because they keep the pieces smaller:

  • authentication backend
  • token or session parsing
  • request identity attachment
  • downstream authorization decisions

That modularity fits Clojure’s preference for smaller composable layers.

A Narrow Buddy-Style Boundary

 1(ns myapp.auth
 2  (:require [buddy.auth :refer [authenticated?]]
 3            [buddy.auth.backends.token :refer [jws-backend]]
 4            [buddy.auth.middleware :refer [wrap-authentication]]))
 5
 6(def auth-backend
 7  (jws-backend {:secret "replace-me"}))
 8
 9(def app
10  (-> routes
11      (wrap-authentication auth-backend)))

The middleware establishes identity. The application still needs explicit authorization checks in the right places.

The example stays intentionally small because auth systems become fragile when too much is hidden. The more important the operation, the more the team should be able to point to the exact code path that:

  • establishes identity
  • checks permission
  • records denial or success where appropriate

Session and Token Design Are Operational Choices

Different web systems want different auth shapes:

  • cookie-backed sessions for server-rendered apps
  • bearer tokens for APIs
  • mixed models for browser + API combinations

The right choice depends on revocation needs, client type, deployment shape, and operational complexity. There is no single “modern” answer that wins everywhere.

Cookie sessions often simplify browser flows and revocation. Tokens often simplify API consumption and distributed edges. Mixed systems frequently need both. The important thing is to match the mechanism to the client boundary instead of choosing one approach because it sounds newer.

Authorization Should Stay Close to the Policy

Good authorization design often means:

  • role checks near route or handler boundaries
  • capability or policy decisions in domain services
  • explicit denial behavior
  • clear auditability for sensitive actions

What usually goes wrong is scattering hidden permission logic across many unrelated handlers.

For high-value actions, permission rules should usually be visible in code review near the operation itself, not buried in an implicit wrapper chain.

Revocation, Expiry, and Logout Need a Real Story

Authentication mechanisms are easy to add and easy to underspecify. The team should know:

  • how sessions expire
  • how logout actually invalidates access
  • how token revocation works, if it matters
  • how stale identity is handled on reconnect or long-lived browser sessions

Without those answers, the system may look secure in happy-path demos and fail under routine lifecycle events.

Sessions, Tokens, and Web Context

The right mechanism depends on the application:

  • server-rendered apps often use sessions and cookies
  • APIs often use bearer tokens
  • mixed systems may need both

The important part is not chasing fashion. It is matching the auth mechanism to the actual web boundary and threat model.

Common Failure Modes

Auth design goes bad when:

  • authentication is treated as if it automatically solves authorization
  • tokens or sessions are accepted without clear revocation or expiry thinking
  • route handlers assume identity data exists without consistent middleware
  • sensitive errors leak too much information

A secure design usually has fewer hidden assumptions than a clever one.

Hiding Permission Rules in Too Many Layers

If route wrappers, handlers, and domain services all perform partial authorization with no clear ownership, security review becomes harder rather than stronger.

Practical Heuristics

Treat identity establishment, session or token handling, and permission policy as separate design problems. Use modular Ring middleware to attach identity cleanly. Keep authorization rules explicit and close to the operations they protect.

Ready to Test Your Knowledge?

Loading quiz…
Revised on Thursday, April 23, 2026