Implementing Security in Onion Architecture — ASP.NET Core 8.0
Security is an integral part of any application. In Onion Architecture, security is implemented as a Cross-cutting Concern. Let us see how we can implement security in ASP.NET Core Web APIs by observing Onion Architecture.

Let us consider the following code snippet:
// Controller - Onion Architecture: Interface Layer
public class UserProfileController : ControllerBase
{
private readonly ISessionContext _sessionContext;
private readonly IApplicationService _applicationService;
public UserProfileController(
ISessionContext sessionContext
IApplicationService applicationService)
{
this._sessionContext = sessionContext;
this._applicationService = applicationService;
}
// Sample save application web api
[HttpGet]
public ActionResult<bool> SaveApplication(
Guid applicationId,
string applicantName)
{
var result = false;
// Is user autenticated?
var authenticated = this._sessionContext.IsAuthenticated();
if (authenticated) {
// If user is autneticated then save application
result = this._applicationService
.SaveApplication(applicationId, applicantName);
}
return this.Ok(result);
}
}
// Repository - Onion Architecture: Domain Services Layer
public class ApplicationRepository: IApplicationRepository
{
private readonly MyDbContext _dbContext;
private readonly ISessionContext _sessionContext;
public ApplicationRepository(
MyDbContext dbContext,
ISessionContext sessionContext)
{
this._dbContext = dbContext;
this._sessionContext = sessionContext;
}
// Sample Repository call.
public ApplicationData SaveApplication(
Guid applicationId,
string applicantName)
{
var userContext = this._sessionContext.User;
// Save application to database
return new SaveApplication()
{
ApplicationId = applicationId,
ApplicantName = applicantName,
// User specific data
UpdatedBy = userContext.UserId,
UpdatedOn = userContext.LocalDateTime
}.Execute(this.DbContext);
}
}In the above code, we have implemented Security as a Cross-cutting concern SessionContext, available at all the Onion Architecture layers.
This enables us to not only secure our WebAPIs but also helps us to uncouple current user information from the business logic making the Service Layer cleaner.
Read my blog Implementing Unit Of Work Pattern Using Entity Framework 8.0 — The Ultimate Guide to understand Repository Pattern used above.
Now, let us look at how the SessionContext is constructed!
Below is a simple implementation of SessionContext:
// Session context that is shareable accross onion architecture layers
public class SessionContext : ISessionContext
{
public readonly ISessionContextAccessor _sessionContextAccessor;
public readonly UserContext _userContext;
public SessionContext(ISessionContextAccessor sessionContextAccessor)
{
this._sessionContextAccessor = sessionContextAccessor;
}
public User UserContext
{
get
{
return this._sessionContextAccessor.GetUserContext();
}
}
public bool IsAuthenticated()
{
return this._sessionContextAccessor.IsAuthenticated();
}
public string SessionId
{
get
{
return this._sessionContextAccessor.SessionId;
}
}
public bool ValidateSession(int slideMinutes)
{
return this._sessionContextAccessor
.ValidateSession(this.SessionId, slideMinutes);
}
public void SlideSession(int slideMinutes)
{
this._sessionContextAccessor
.SlideSession(this.SessionId, slideMinutes);
}
public void ExpireSession()
{
this._sessionContextAccessor.ExpireSession(this.SessionId);
}
public DateTime? GetSessionExpiration() {
return this._sessionContextAccessor.GetSessionExpiration(this.SessionId);
}
}As you can see, SessionContext is just a Delegation to ISessionContextAccessor.
This is because SessionContext is a Cross-cutting concern and must reside at the lowest level so that it can be referenced by all the Onion Architecture layers, whereas we can Implement ISessionContextAccessor at the highest layer which is the Interface/Controller layer.
Let us now see, how ISessionContextAccessor is implemented:
public class SessionContextAccessor : ISessionContextAccessor
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ISessionContextService _sessionContextService;
public SessionContextAccessor(
IHttpContextAccessor httpContextAccessor,
ISessionContextService sessionContextService)
{
this._httpContextAccessor = httpContextAccessor;
this._sessionContextService = sessionContextService;
}
public string SessionId
{
get
{
// Implement your own way to persist session information.
return this._httpContextAccessor
.HttpContext.Request.Cookies["sessionId"].Value;
}
}
public UserContext GetUserContext()
{
var userModel = this._sessionContextService
.GetUserBySessionId(this.sessionId);
if (userModel != null)
{
return new UserContext
{
UserId = userModel.UserId,
FirstName = userModel.FirstName,
LastName = userModel.LastName,
EmailAddress = userModel.EmailAddress,
PhoneNumber = userModel.PhoneNumber
};
}
return null;
}
public bool ValidateSession(int slideMinutes)
{
return this._sessionContextService
.ValidateSession(this.sessionId, slideMinutes);
}
public void SlideSession(int slideMinutes)
{
this._sessionContextService
.SlideSession(this.sessionId, slideMinutes);
}
public void ExpireSession()
{
this._sessionContextService
.ExpireSession(this.sessionId);
}
public bool IsAuthenticated()
{
return this._sessionContextService
.IsAuthenticated(this.sessionId);
}
public DateTime? GetSessionExpiration()
{
return this._sessionContextService
.GetUserSessionExpiration(this.sessionId);
}
}Above, SessionContextAccessor is again a delegation of a custom SessionContextService service class where we are accessing Session ID through a cookie. Feel free to change the strategy to persist session information yourself whether it be a Claim Provider or any other means.
That is it!
we have fully baked security into our Web APIs.
Where to go from here?
we can extend the Session Context to add security at a granular level such as building permission domain models and using them in the context above.
We can also, implement IAuthorizationFilter to have declarative security to decorate Web APIs.
🔔 Follow me for more content like this! 🔔
Did this article help you today? Buy me a cup of coffee☕ to keep me going!






