Internal Services
Moka.Auth is built on a set of core services that handle authentication, user management, roles, permissions, and API keys. This guide explains the internal architecture and how these services work together.
Core Services Overview
AuthService (IAuthService)
The authentication service handles user authentication and token management:
public interface IAuthService{ Task<AuthResult> AuthenticateAsync(string username, string password); Task<string> GenerateTokenAsync(MokaUser user); Task<ClaimsPrincipal> CreateClaimsPrincipalAsync(MokaUser user); Task SignInAsync(MokaUser user, bool isPersistent = false); Task SignOutAsync(); Task<bool> ValidateTokenAsync(string token);}Multiple authentication providers implement this interface:
JwtAuthService: JSON Web Token authenticationCookieAuthService: Cookie-based authenticationApiKeyAuthService: API key authenticationOpenIdAuthService: OpenID Connect authentication
UserService (IUserService)
Manages user operations including:
- User CRUD operations
- Role assignments
- Permission assignments
- API key management
Key capabilities:
public interface IUserService{ // User Management Task<MokaUser?> FindByIdAsync(string userId); Task<MokaUser?> FindByNameAsync(string userName); Task<MokaUser?> FindByEmailAsync(string email); Task<bool> CreateAsync(MokaUser user, string password); Task<bool> UpdateAsync(MokaUser user); Task<bool> DeleteAsync(string userId);
// Role Management Task<bool> AddToRoleAsync(string userId, string roleName); Task<bool> RemoveFromRoleAsync(string userId, string roleName); Task<List<string>> GetRolesAsync(string userId);
// Permission Management Task<bool> AddPermissionAsync(string userId, int permissionId); Task<bool> RemovePermissionAsync(string userId, int permissionId); Task<List<MokaPermission>> GetPermissionsAsync(string userId); Task<List<MokaPermission>> GetEffectivePermissionsAsync(string userId);
// API Key Management Task<MokaApiKey> CreateApiKeyAsync(string userId, string name, DateTimeOffset? expiresAt); Task<bool> DeleteApiKeyAsync(int apiKeyId); Task<List<MokaApiKey>> GetApiKeysAsync(string userId);}RoleService (IRoleService)
Handles role-based access control:
- Role CRUD operations
- Permission assignments to roles
- User-role relationships
public interface IRoleService{ Task<MokaRole?> FindByIdAsync(int roleId); Task<MokaRole?> FindByNameAsync(string roleName); Task<bool> CreateAsync(MokaRole role); Task<bool> UpdateAsync(MokaRole role); Task<bool> DeleteAsync(int roleId); Task<List<MokaRole>> GetAllRolesAsync(); Task<bool> AddPermissionAsync(int roleId, int permissionId); Task<bool> RemovePermissionAsync(int roleId, int permissionId);}PermissionService (IPermissionService)
Manages the permission system:
- Permission CRUD operations
- Permission validation
- Permission inheritance
public interface IPermissionService{ Task<MokaPermission?> FindByIdAsync(int permissionId); Task<MokaPermission?> FindByNameAsync(string permissionName); Task<bool> CreateAsync(MokaPermission permission); Task<bool> UpdateAsync(MokaPermission permission); Task<bool> DeleteAsync(int permissionId); Task<List<MokaPermission>> GetAllPermissionsAsync();}ImpersonationService
Enables administrative users to impersonate other users for troubleshooting and support purposes:
public class ImpersonationService{ public Task<(bool Success, string? Token)> ImpersonateUserAsync(string targetUserId); public Task<(bool Success, string? Token)> EndImpersonationAsync(); public bool IsImpersonating(); public Task<MokaUser?> GetImpersonatedUserAsync(); public Task<MokaUser?> GetOriginalUserAsync();}Key capabilities:
- Securely switch to another user’s identity
- Track the original user during impersonation
- End impersonation sessions and return to original user identity
- Check impersonation status
- Access both original and impersonated user details
Service Interactions
Authentication Flow
- User provides credentials
AuthServicevalidates credentialsUserServiceretrieves user detailsRoleServiceandPermissionServicegather user’s roles and permissionsAuthServicegenerates appropriate token or cookie
// Example authentication flowvar authResult = await _authService.AuthenticateAsync(username, password);if (authResult.Succeeded){ var user = await _userService.FindByNameAsync(username); var roles = await _userService.GetRolesAsync(user.Id); var permissions = await _userService.GetEffectivePermissionsAsync(user.Id); var token = await _authService.GenerateTokenAsync(user);}Permission Resolution
Permissions are resolved through multiple layers:
- Direct user permissions
- Role-based permissions
- Inherited permissions
// Example permission check flowvar user = await _userService.FindByIdAsync(userId);var directPermissions = await _userService.GetPermissionsAsync(userId);var roles = await _userService.GetRolesAsync(userId);var rolePermissions = new List<MokaPermission>();
foreach (var role in roles){ var rolePerms = await _roleService.GetPermissionsAsync(role.Id); rolePermissions.AddRange(rolePerms);}
var effectivePermissions = directPermissions.Union(rolePermissions);Impersonation Flow
The impersonation system allows administrators to temporarily act as another user:
- Admin initiates impersonation with a target user ID
- Original admin’s identity is securely stored
- Admin receives authentication token for the target user
- System tracks impersonation state with secure HTTP-only cookies
- Admin can end impersonation and return to their original identity
// Example impersonation flowvar impersonationService = serviceProvider.GetRequiredService<ImpersonationService>();
// Start impersonationvar (success, token) = await impersonationService.ImpersonateUserAsync(targetUserId);if (success){ // Use token to authenticate as impersonated user // ...
// Check if currently impersonating bool isImpersonating = impersonationService.IsImpersonating();
// Get original admin user if needed var originalUser = await impersonationService.GetOriginalUserAsync();
// End impersonation when finished var (endSuccess, adminToken) = await impersonationService.EndImpersonationAsync();}Customizing Services
Moka.Auth uses standard dependency injection, allowing you to replace any of the default service implementations with your own custom versions.
Creating Custom Services
- Create your custom service implementation:
public class CustomUserService : IUserService{ private readonly IMokaAuthRepository<MokaAuthDbContext> _repository;
public CustomUserService(IMokaAuthRepository<MokaAuthDbContext> repository) { _repository = repository; }
// Implement IUserService methods with custom logic public async Task<MokaUser?> FindByIdAsync(string userId) { // Custom implementation var user = await _repository.GetUserByIdAsync(userId); // Add custom logic here return user; }
// Implement other interface methods...}- Register your custom service:
// First add Moka.Auth with your configurationservices.AddMokaAuth(options => { // Your auth options here});
// Then register your custom service - this will replace the default implementationservices.AddScoped<IUserService, CustomUserService>();Available Services for Customization
You can customize any of these services by implementing their interfaces:
// Core servicesservices.AddScoped<IUserService, CustomUserService>();services.AddScoped<IRoleService, CustomRoleService>();services.AddScoped<IPermissionService, CustomPermissionService>();services.AddScoped<ImpersonationService, CustomImpersonationService>();
// Auth providersservices.AddScoped<IAuthService, CustomAuthService>();Database Integration
All services use the IMokaAuthRepository<TContext> interface for data access:
- Entity Framework Core implementation provided by default
- Custom implementations possible for different databases
- Repository pattern ensures consistent data access
public interface IMokaAuthRepository<TContext> where TContext : DbContext{ // User Management Task<MokaUser> GetUserByIdAsync(string userId); Task<MokaUser> GetUserByUsernameAsync(string username); Task<MokaUser> GetUserByEmailAsync(string email); Task<IEnumerable<MokaUser>> GetUsersAsync(int skip = 0, int take = 10, Expression<Func<MokaUser, bool>>? predicate = null); Task<IdentityResult> CreateUserAsync(MokaUser user, string password); Task<IdentityResult> UpdateUserAsync(MokaUser user); Task<IdentityResult> DeleteUserAsync(string userId);
// Role Management Task<MokaRole> GetRoleByIdAsync(string roleId); Task<MokaRole> GetRoleByNameAsync(string roleName); Task<IEnumerable<MokaRole>> GetRolesAsync(Expression<Func<MokaRole, bool>> predicate = null); Task<IdentityResult> CreateRoleAsync(MokaRole role); Task<IdentityResult> UpdateRoleAsync(MokaRole role); Task<IdentityResult> DeleteRoleAsync(string roleId);
// Permission Management Task<MokaPermission> GetPermissionByIdAsync(int permissionId); Task<MokaPermission> GetPermissionByNameAsync(string permissionName); Task<IEnumerable<MokaPermission>> GetPermissionsAsync(Expression<Func<MokaPermission, bool>> predicate = null); Task<IdentityResult> CreatePermissionAsync(MokaPermission permission); Task<IdentityResult> UpdatePermissionAsync(MokaPermission permission); Task<IdentityResult> DeletePermissionAsync(int permissionId);
// User-Role Relationships Task<IEnumerable<MokaRole>> GetUserRolesAsync(string userId); Task<IdentityResult> AssignRoleToUserAsync(string userId, string roleName); Task<IdentityResult> RemoveRoleFromUserAsync(string userId, string roleName);
// Permission Assignments Task<IEnumerable<MokaPermission>> GetRolePermissionsAsync(string roleId); Task<IdentityResult> AssignPermissionToRoleAsync(string roleId, int permissionId); Task<IdentityResult> RemovePermissionFromRoleAsync(string roleId, int permissionId); Task<IEnumerable<MokaPermission>> GetUserPermissionsAsync(string userId); Task<IdentityResult> AssignPermissionToUserAsync(string userId, int permissionId); Task<IdentityResult> RemovePermissionFromUserAsync(string userId, int permissionId);
// API Key Management Task<MokaApiKey> GetApiKeyByIdAsync(int apiKeyId); Task<IEnumerable<MokaApiKey>> GetUserApiKeysAsync(string userId, Expression<Func<MokaApiKey, bool>> predicate = null); Task<IEnumerable<MokaApiKey>> GetAllApiKeysAsync(Expression<Func<MokaApiKey, bool>> predicate = null); Task<IdentityResult> CreateApiKeyAsync(MokaApiKey apiKey); Task<IdentityResult> UpdateApiKeyAsync(MokaApiKey apiKey); Task<IdentityResult> DeleteApiKeyAsync(int apiKeyId);
// API Key Authorization Task<IdentityResult> AssignRoleToApiKeyAsync(int apiKeyId, string roleId); Task<IdentityResult> RemoveRoleFromApiKeyAsync(int apiKeyId, string roleId); Task<IEnumerable<MokaRole>> GetApiKeyRolesAsync(int apiKeyId); Task<IdentityResult> AssignPermissionToApiKeyAsync(int apiKeyId, int permissionId); Task<IdentityResult> RemovePermissionFromApiKeyAsync(int apiKeyId, int permissionId); Task<IEnumerable<MokaPermission>> GetApiKeyPermissionsAsync(int apiKeyId);}The repository interface supports:
- Expression-based filtering with LINQ predicates
- Flexible querying with pagination support
- Strongly-typed entities with Identity integration
- Comprehensive API key management and authorization
- Complete role and permission assignment operations