Sponsor: Using RabbitMQ or Azure Service Bus in your .NET systems? Well, you could just use their SDKs and roll your own serialization, routing, outbox, retries, and telemetry. I mean, seriously, how hard could it be?
I’m diving into a super common question that’s really important: where should your authorization live? Should it live within your domain or your application layer? I am going to show some real world code examples and some simple guidelines so you can keep your software architecture consistent and avoid authorization code scattered everywhere.
YouTube
Check out my YouTube channel, where I post all kinds of content on Software Architecture & Design, including this video showing everything in this post.
Authentication versus Authorization
I want to make the distinction because a lot of people mix these up. Authentication is who are you. That is not what we are talking about. What we are talking about is authorization, which is what you are allowed to do. I want to set that in again: what you are allowed to do. That phrasing will guide the guidelines and code samples I’m about to present.
Think of a typical flow. A client makes a request to our application and provides some identity for the client making that request. From there we perform authorization to determine whether the action being attempted is allowed. If it passes, we then hit our database or perform the business operation.
The Question: Domain or Application Layer?

When people start modeling their domain and using domain driven design, they ask: I previously had authorization in one place, but now some thing feels like a business rule and should live in my domain. So I am going to make the application call into the domain, fetch the domain object or aggregate, and let the domain do authorization. Which is it? Should the logic be inside the domain or a level up in the application layer?
What are you allowed to do?
Bank Account Example
Imagine a bank account in the domain with a withdraw method. Inside that withdraw method we have logic like: if the current user making the request is not the owner of the account then throw. Should that logic live here within the domain or should it be in the application layer?
Here is a guideline I use. If the domain needs to know business entities, values, or state transitions, then that logic should stay inside the domain model. If the domain needs to know who is making the request, meaning identity, roles, claims, then those concerns should be handled outside of your domain model in your application layer.
In the bank account example our domain does not need to care about identity. The domain needs to care about business rules like you can not withdraw more than the balance. That is a business rule and belongs in the domain. The identity portion can be removed from the domain and placed up in the application layer, where you check whether the requester is allowed to act on that account. Once that check passes, call into the domain to perform the withdrawal.
Vacation Request Example
Now consider a vacation request. We have an Employee which specifies whether the employee is a manager or not. We have a VacationRequest and an approve method where we pass in the approver. Inside approve there is logic like: if the approver is not a manager then throw.
This is fine inside the domain because an employee is a business concept and the rule that the approver must be a manager is a business rule. This is not leaking information about who is making the request. This is not authorization in the sense of verifying identity and permissions. It is validating behavior. Put another way, it is not about who can access a system feature, it is about what the business considers valid behavior.
Shipment and Dispatcher Example
Consider a dispatcher who takes orders and assigns a vehicle and driver to perform deliveries. The dispatcher has an assigned region. A shipment has a region. When assigning a driver to a shipment you might have a business rule like: if the dispatcher assigned region does not match the shipment region then throw. That is business logic. The domain cares about whether that association is valid in the context of the business process.
On the other hand, authorization is about who can do the assignment in the system. Perhaps only users with the role dispatch manager may assign a dispatcher to a shipment. That is a security check at the application layer. For example, you might implement a policy in ASP.NET Core that requires a dispatch manager role. When the request comes in, check that the caller has that role. If they do, proceed to the domain operation. If you let the domain know about the dispatch manager as a user, the domain drifts away from modeling the business capability and into handling access control concerns.
Guidelines to Decide Where Authorization Belongs
- If a rule controls who can access a system feature or perform an operation, treat it as security and handle it in the application layer.
- If a rule controls how the business process works and what the business considers valid behavior, implement it as business logic in the domain layer.
- If the logic depends on identity, roles, or claims, consider keeping that logic outside the domain and enforcing it in the application layer.
- If the logic depends on business entities, values, or state transitions, keep it inside the domain model.
Why Leaking Identity into the Domain Causes Problems
Here is an example that explains why leaking identity into the domain is problematic. Imagine a User with a resetPassword method that sets a temporary password. Inside resetPassword we check if the user making the request is the same user as the user object, and if not, we throw. That seems reasonable at first glance, but it breaks reuse.
What happens if an admin needs to reset a password for someone else? What happens if a service or another entry point needs to create a user on behalf of another? If the domain insists that resetPassword can only be invoked by the same user, you can no longer reuse that method for other legitimate flows. The real concern is who is performing the action, and that belongs on the application layer where the caller and entry point are known.
Authorization is one of those things that seems simple until it is not. You add checks and scatter them across your domain, and then it becomes a gray area of what is an actual business rule and what is authorization tied to the caller.
Authorization: Domain or Application Layer?
Keep a clear distinction between business rules and access control. If it is about what the business considers valid behavior, let the domain own it. If it is about who can perform an operation based on identity, roles, or claims, put that in the application layer. Following these guidelines will help you avoid authorization logic scattered throughout your domain and will keep your domain model focused on modeling the business capabilities.
Join CodeOpinon!
Developer-level members of my Patreon or YouTube channel get access to a private Discord server to chat with other developers about Software Architecture and Design and access to source code for any working demo application I post on my blog or YouTube. Check out my Patreon or YouTube Membership for more info.