2

I have seen some Bounded Context examples to learn DDD.

In those examples, the User Access bounded context (register, login, authorization...) is considered a generic bounded context and could be a shared kernel.

I think it's true. It's generic because, without it, the application couldn't work, and we could use the existing IAM system to do this. It is a shared kernel because almost bounded contexts require it.

But I can't find the right place to put it in the Clean Architecture/Onion Architecture.

It appears in the application layer for authorization.

It appears in the domain layer because... it is a bounded context, duh.

The user could appear in some other bounded contexts, but should not exist in some bounded contexts that do not require the user data like Reporting Bounded Context, etc.

This confuses me a lot.

Could you tell me where to put the user access bounded context in the Clean Architecture and why should I put it there?

3 Answers 3

1

You sort of answered your own question right at the end. On most applications, The login system does not belong in the domain layer.

Unless your application focuses on authentication (e.g. you are developing security software that focuses on user sessions), the authentication logic belongs in the application layer.

Furthermore, in most cases, it is better to use a trusted third-party library for critical security components (in which case your user access would be a very light wrapper class / script which initializes the library and/or calls a few methods). No matter how much experience you have, chances are that when you write your own logic, it will be less secure than that which was written by a team of security software professionals.

If the third party library is an interface to a standalone application (e.g. a daemon), then it is likely. that their domain layer contains a user access aggregate (or more than one, depending on its size and complexity) in its domain layer.

2
  • Since the authentication is used in multiple bounded contexts, should I put it in the shared directory or a separated module? If I should use the third-party library, where should I place it in the onion architecture? Commented Dec 1, 2021 at 1:55
  • I disagree with this answer in that I think it leaves an important distinction ambiguous. If the current codebase has written its own login system, then the login system is part of the domain. However, if the login system comes from an external library, then this library should be referenced by the application layer. In a third scenario, when using an external identity provider, you're going to put code in both the infrastructure layer (to talk to the external identity provider) and the application layer (to enforce the access control based on the identity provider's data).
    – Flater
    Commented Feb 13, 2023 at 23:21
0

It might help you think of "Users" as an abstraction. Its meaning or concreteness varies depending on the layer you are working on. Perhaps, you have modelled User only once and, in consequence, appears everywhere. Basically, you have imposed a strict "idea" of what a User is and forced all the boundaries to deal with it.

But, could boundaries have different "meanings" or purposes for the word User? Absolutely. Rewording might help you to think about it.

From the application layer standpoint. What's a user? What does this layers needs from the User to work? It's only a login password? A name? Roles? Could we rename User to Account? Or Principal?

Now, from the business layer standpoint. What's a user? Personal data? A shipping and billing address? What does the business need from the User to work?

Finally, from the core layer standpoint. What's a user? A name? An ID? What does the core need from the User to work?

Of course, in the end, all three things are the same. All three represent an actor of the system that incarnates all these properties. A person with a name, shipping and billing addresses, credentials, etc. But each layer takes only what it needs from it.

When I said, "think of Users as an abstraction", I was literaly suggestion making the notion of "User" an abstract element of the domain and implement concrete "Users" in outer layers.

To illustrate with an example. Do you think that all the "boundaries"/"departments" in companies like Amazon, do understand the word "User" in the same way? Probably, each will give you a different description of what a user is, regardless they will all be speaking about the same. About you (the customer/user/Ngoc Nguyen/shipping address X, billing address Y, etc).

0

The short answer

I suspect your question stems from wanting to avoid having another context (e.g. the Orders application layer) depend on the User Access domain logic.

The direct answer to that part of the question is that it is perfectly okay to do so, because the application of the user access bounded context is inherently intended to be used by the application layer (across all bounded contexts that need user access control).


The longer answer

In most app features you develop, there are two parts of the story. Sorry for being vague but the naming here is a bit fuzzy. I'm going to call these two stages the setup and the application.

In order to disambiguate, I'm going to refer to software applications as "apps". When I say "application", I mean the stage that I just labeled.

The setup is where you prepare your information, not to be used right now but to have it readily available at a later stage. This could be something like:

  • A police app which allows you to enter fines/infractions/arrests
  • A library app allowing you to enter its book collection into the database
  • Defining user access rights for an app's resources

When you get to the application stage, you use your setup in order to achieve the goal you intend to achieve. For the given examples:

  • You can review a person's criminal history during e.g. a police stop or a court case
  • You are able to check out a book in the app
  • You can decide whether the current user is allowed access to a particular app resource

I picked these three examples for a very particular reason. In regards to their setup, it's always the same CRUD principle. Nothing really changes here. But the application stage is notably different in that:

  • The police app is a simple data-in-data-out app, and the application of this setup is applied outside of the app (by the end users having access to this data and using it in the real world)
  • The library app uses the setup in order to supply a secondary app feature: checking out a book. The application here is applied to the app itself, as part of a public (end user facing) feature.
  • The access control uses the setup in order to support its own internal workings. The application here is applied to the app's internal/private logic which the end user is not privy to.

Okay, this was a whole lot of setup, but now comes the application (this pun is totally intended and I dearly apologize if you're groaning):

A bounded context can contain setup, its own application, the application of another bounded context, or any combination of these. There is no One True Answer to your question, because this can vary based on context.

Specifically, in the given examples:

  • The criminal records bounded context can logically only contain setup, since the application is not found within the app.
  • The books bounded context only contains setup, but there is a second checkout bounded context which contains the application of the books context
  • The user access bounded context is only setup, but effectively every bounded context in the app (which requires user access control) contains the application (including the user access bounded context itself, since not every user can set the user access rights)

This brings me to your statement:

In those examples, the User Access bounded context (register, login, authorization...) is considered a generic bounded context and could be a shared kernel.

When dealing with user access, what you're going to find is that you have both a neatly defined bounded context that contains all of the setup; and you're also going to be peppering the entire set of bounded contexts (which require user access control) with references to that user access bounded context (what you call the shared kernel), because that is the application of that setup.

But I can't find the right place to put it in the Clean Architecture/Onion Architecture.

Due to the above conclusion, it's going to live in more than one place. However, each part has its own specific place that it belongs.

It appears in the application layer for authorization.
It appears in the domain layer because... it is a bounded context, duh.

I chose the name "application" for this stage for a really similar reason why people often refer to the "application" layer: it is where you start using (applying) the things that you've built.

In this particular case of user access control, there is a neat split whereby the setup belongs in the domain layer (because it is a CRUD bounded context just like any other) and the application of that setup belongs to the application layer (as it gets used by every bounded context which needs to provide user access control).

I suspect your question stems from wanting to avoid having another context (e.g. the Orders application layer) depend on the User Access domain logic. The direct answer to that part of the question is that it is perfectly okay to do so, because the application of the user access bounded context is inherently intended to be used by the application layer (across all bounded contexts that need user access control).

The user could appear in some other bounded contexts, but should not exist in some bounded contexts that do not require the user data

Two things:

  • You're going to find that more often than not, the user bounded context and the user access bounded context are two different things. If you are dealing with cases where you want to refer to users without referring to their access, that you're going to need to separate these bounded contexts.
  • Obviously, the application of user access control is only needed in bounded contexts whose resources should be access controlled. If some of your app's resources are publicly available, then you simply don't need to reference any user access control. That's perfectly fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.