Broken Access Control in Hanami with Bearer Tokens
Broken Access Control in Hanami with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Broken Access Control occurs when authorization checks are missing or incorrectly enforced, allowing authenticated users to access or modify resources that should be restricted. In a Hanami application that relies on Bearer Tokens for API authentication, the combination of token-based auth and missing or inconsistent authorization logic can expose sensitive endpoints to unauthorized access.
Hanami does not enforce authorization by default; it expects developers to explicitly gate actions and data access. If an API endpoint validates the presence of a Bearer Token (e.g., via a header such as Authorization: Bearer <token>) but does not verify whether the token’s associated scope, role, or user identity permits the requested operation, an attacker who obtains or guesses a valid token can traverse the application horizontally or vertically.
Consider an endpoint like /api/v1/accounts/:id. A Hanami controller might authenticate the request by verifying the Bearer Token and loading an account record, but if it uses the token’s user ID only to confirm login status and does not compare the account ID in the URL to the token’s associated account, an attacker can change the ID and view or modify other accounts. This is a classic Level of Access (BOLA) / Insecure Direct Object Reference (IDOR) scenario, cataloged in the OWASP API Top 10 and commonly observed in token-based APIs where object-level authorization is omitted.
Real-world attack patterns include enumeration of IDs with a valid but low-privilege token, privilege escalation via tampered tokens that include elevated scopes (if the token is self-contained and not validated server-side), and data exposure through insufficient property-level authorization. For example, an attacker might send a request with a Bearer Token belonging to a read-only user to POST /api/v1/admin/settings and, if the server only checks for a token rather than a specific admin scope, the change proceeds. Such issues are not theoretical; they map to real vulnerabilities tracked in public CVEs where missing authorization checks in API routes allowed unauthorized data access or modification.
Because middleBrick scans the unauthenticated attack surface and runs checks such as Authentication, BOLA/IDOR, and Property Authorization in parallel, it can surface these classes of problems against a Hanami API protected only by Bearer Tokens. The scanner does not assume that authentication equals authorization; it tests whether endpoints properly enforce scope- and resource-level checks, returning findings with severity ratings and remediation guidance to help developers tighten access controls.
Bearer Tokens-Specific Remediation in Hanami — concrete code fixes
To remediate Broken Access Control when using Bearer Tokens in Hanami, you must couple token validation with explicit, server-side authorization checks for every sensitive operation. Below are concrete patterns and code examples you can apply.
1. Validate token and enforce scope-based authorization
Ensure your controller validates the Bearer Token and enforces required scopes or roles before proceeding. Avoid relying on a simple presence check.
module Web::Controllers::Accounts
class Show
include Hanami::Action
def call(params)
token = params[:header]["authorization"]&.to_s.sub("Bearer ", "")
halt [401, { error: "Unauthorized" }.to_json] unless token_valid?(token)
account = AccountRepository.new.find(params[:id])
halt [403, { error: "Forbidden" }.to_json] unless account && policy(account).read?
self.body = { account: account }.to_json
end
private
def token_valid?(token)
# Verify signature/issuer/expiry using your auth library (e.g., JWT)
# Return true only if token is valid and contains required scope/roles
end
def policy(account)
TokenPolicy.new(token: token, account: account)
end
end
end
2. Apply object-level authorization for resource ownership
When an endpoint includes an identifier (e.g., account ID), compare it to the identifier associated with the token to prevent IDOR.
module Web::Controllers::Transactions
class Create
include Hanami::Action
def call(params)
user_id = current_user_id_from_token
amount = params[:body][:amount]
halt [403, { error: "Forbidden" }.to_json] unless params[:body][:account_id] == user_id
# Proceed with transaction creation for this user’s account only
Transactions::Create.new.call(user_id: user_id, amount: amount, account_id: params[:body][:account_id])
self.status = 201
end
end
end
3. Use a policy object to centralize authorization logic
Define a policy class that encapsulates rules for each resource and reuse it across actions.
class TokenPolicy
def initialize(token:, account:)
@token = token
@account = account
end
def read?
token_scopes.include?(:read_accounts) || token_user_id == account.user_id
end
def write?
token_scopes.include?(:write_accounts) || token_user_id == account.user_id
end
private
attr_reader :token, :account
def token_user_id
# decode or fetch from token store
end
def token_scopes
# extract scopes from token
end
end
4. Enforce authorization at the route level where applicable
For APIs, consider scoping routes and using constraints or middleware to ensure tokens carry minimal required scopes. Combine this with per-action checks for defense in depth.
# config/routes.rb
Rack::Builder.new do
use Rack::Auth::Token, realm: "API", "scope" => "read_accounts"
run Hanami.app
end
These examples illustrate how to bind Bearer Token validation to explicit, resource-level authorization in Hanami. By doing so, you reduce the risk of Broken Access Control and align with best practices for token-based API security.