Skip to content

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 authentication
  • CookieAuthService: Cookie-based authentication
  • ApiKeyAuthService: API key authentication
  • OpenIdAuthService: 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

  1. User provides credentials
  2. AuthService validates credentials
  3. UserService retrieves user details
  4. RoleService and PermissionService gather user’s roles and permissions
  5. AuthService generates appropriate token or cookie
// Example authentication flow
var 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:

  1. Direct user permissions
  2. Role-based permissions
  3. Inherited permissions
// Example permission check flow
var 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:

  1. Admin initiates impersonation with a target user ID
  2. Original admin’s identity is securely stored
  3. Admin receives authentication token for the target user
  4. System tracks impersonation state with secure HTTP-only cookies
  5. Admin can end impersonation and return to their original identity
// Example impersonation flow
var impersonationService = serviceProvider.GetRequiredService<ImpersonationService>();
// Start impersonation
var (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

  1. 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...
}
  1. Register your custom service:
// First add Moka.Auth with your configuration
services.AddMokaAuth(options => {
// Your auth options here
});
// Then register your custom service - this will replace the default implementation
services.AddScoped<IUserService, CustomUserService>();

Available Services for Customization

You can customize any of these services by implementing their interfaces:

// Core services
services.AddScoped<IUserService, CustomUserService>();
services.AddScoped<IRoleService, CustomRoleService>();
services.AddScoped<IPermissionService, CustomPermissionService>();
services.AddScoped<ImpersonationService, CustomImpersonationService>();
// Auth providers
services.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