Security Features
GrydAuth includes enterprise-grade security features to protect your application against common threats.
Rate Limiting
Protect endpoints against brute-force attacks and abuse.
Configuration
csharp
builder.Services.AddGrydAuth(options =>
{
options.RateLimiting.Enabled = true;
// Global rate limit
options.RateLimiting.GlobalLimit = new RateLimitConfig
{
PermitLimit = 1000,
Window = TimeSpan.FromMinutes(1)
};
// Auth endpoints (stricter)
options.RateLimiting.AuthEndpointsLimit = new RateLimitConfig
{
PermitLimit = 10,
Window = TimeSpan.FromMinutes(1)
};
// Per-user limits
options.RateLimiting.PerUserLimit = new RateLimitConfig
{
PermitLimit = 100,
Window = TimeSpan.FromMinutes(1)
};
});Custom Rate Limit Policies
csharp
builder.Services.AddRateLimiter(options =>
{
options.AddPolicy("sensitive-operations", context =>
RateLimitPartition.GetFixedWindowLimiter(
partitionKey: context.User.Identity?.Name ?? context.Connection.RemoteIpAddress?.ToString(),
factory: _ => new FixedWindowRateLimiterOptions
{
PermitLimit = 5,
Window = TimeSpan.FromMinutes(15)
}));
});
// Usage
[EnableRateLimiting("sensitive-operations")]
public IActionResult DeleteAccount() { ... }Audit Logging
Track all security-related events.
Enable Audit Logging
csharp
builder.Services.AddGrydAuth(options =>
{
options.AuditLogging.Enabled = true;
options.AuditLogging.LogSuccessfulLogins = true;
options.AuditLogging.LogFailedLogins = true;
options.AuditLogging.LogPermissionChanges = true;
options.AuditLogging.LogTokenOperations = true;
options.AuditLogging.RetentionDays = 90;
});Audit Events
| Event | Description |
|---|---|
UserLogin | Successful login |
UserLoginFailed | Failed login attempt |
UserLogout | User logout |
UserRegistered | New user registration |
PasswordChanged | Password change |
PasswordResetRequested | Password reset request |
RoleAssigned | Role assigned to user |
RoleRevoked | Role removed from user |
PermissionGranted | Permission granted |
PermissionRevoked | Permission revoked |
TokenRefreshed | Token refreshed |
TokenRevoked | Token manually revoked |
AccountLocked | Account locked due to failed attempts |
AccountUnlocked | Account unlocked |
Querying Audit Logs
http
GET /api/audit-logs?userId=550e8400-e29b-41d4-a716-446655440000&eventType=UserLogin&from=2026-01-01&to=2026-01-31
Authorization: Bearer {admin-token}Response:
json
{
"items": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"userId": "550e8400-e29b-41d4-a716-446655440000",
"eventType": "UserLogin",
"ipAddress": "192.168.1.100",
"userAgent": "Mozilla/5.0...",
"timestamp": "2026-01-15T10:30:00Z",
"success": true,
"metadata": {
"method": "Password",
"mfaUsed": false
}
}
],
"totalCount": 42,
"page": 1,
"pageSize": 20
}Custom Audit Events
csharp
public class OrderService
{
private readonly IAuditLogger _auditLogger;
public async Task<Order> CreateOrderAsync(CreateOrderRequest request)
{
var order = await _orderRepository.CreateAsync(request);
await _auditLogger.LogAsync(new AuditEvent
{
EventType = "OrderCreated",
EntityType = "Order",
EntityId = order.Id.ToString(),
Metadata = new Dictionary<string, object>
{
["amount"] = order.TotalAmount,
["items"] = order.Items.Count
}
});
return order;
}
}Geo-Location Tracking
Track login locations and detect suspicious activity.
Configuration
csharp
builder.Services.AddGrydAuth(options =>
{
options.GeoLocation.Enabled = true;
options.GeoLocation.Provider = GeoLocationProvider.MaxMind;
options.GeoLocation.BlockSuspiciousLogins = true;
options.GeoLocation.TrustedCountries = ["US", "CA", "GB", "DE"];
});MaxMind GeoIP Setup
csharp
builder.Services.AddMaxMindGeoIp(options =>
{
options.AccountId = Configuration["MaxMind:AccountId"]!;
options.LicenseKey = Configuration["MaxMind:LicenseKey"]!;
options.DatabasePath = Path.Combine(AppContext.BaseDirectory, "GeoLite2-City.mmdb");
options.AutoUpdate = true;
options.UpdateIntervalDays = 7;
});Location-Based Alerts
csharp
public class LocationSecurityHandler : ILoginEventHandler
{
private readonly INotificationService _notifications;
private readonly IGeoLocationService _geoLocation;
public async Task HandleLoginAsync(LoginEvent loginEvent)
{
var currentLocation = await _geoLocation.GetLocationAsync(loginEvent.IpAddress);
var lastLocation = await GetLastLoginLocationAsync(loginEvent.UserId);
if (lastLocation != null && IsUnusualLocation(currentLocation, lastLocation))
{
await _notifications.SendAsync(
loginEvent.UserId,
"New Login Location",
$"We detected a login from {currentLocation.City}, {currentLocation.Country}. " +
"If this wasn't you, please change your password immediately."
);
}
}
private bool IsUnusualLocation(GeoLocation current, GeoLocation last)
{
// Check if locations are suspiciously far apart for the time elapsed
var distance = CalculateDistance(current, last);
var timeElapsed = current.Timestamp - last.Timestamp;
var maxPossibleSpeed = 1000; // km/h (roughly commercial airline speed)
return distance / timeElapsed.TotalHours > maxPossibleSpeed;
}
}Token Security
Token Invalidation
csharp
// Invalidate specific token
await _tokenService.RevokeTokenAsync(refreshToken);
// Invalidate all user tokens
await _tokenService.RevokeAllUserTokensAsync(userId);
// Invalidate with reason
await _tokenService.RevokeTokenAsync(refreshToken, new RevocationReason
{
Type = RevocationType.SecurityConcern,
Description = "Suspicious activity detected"
});Token Versioning
GrydAuth uses token versioning to invalidate tokens instantly:
csharp
public class User : AggregateRoot<Guid>
{
public long TokenVersion { get; private set; } = 1;
public void IncrementTokenVersion()
{
TokenVersion++;
AddDomainEvent(new TokensInvalidatedEvent(Id, TokenVersion));
}
}All tokens issued before the current version are automatically rejected.
Blacklist Caching
csharp
builder.Services.AddGrydAuth(options =>
{
options.TokenBlacklist.Enabled = true;
options.TokenBlacklist.CacheProvider = BlacklistCacheProvider.Redis;
options.TokenBlacklist.CacheDuration = TimeSpan.FromDays(7);
});
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = Configuration.GetConnectionString("Redis");
options.InstanceName = "GrydAuth:";
});Security Headers
GrydAuth automatically adds security headers:
csharp
app.UseGrydAuth(); // Adds security middleware
// Headers added:
// X-Content-Type-Options: nosniff
// X-Frame-Options: DENY
// X-XSS-Protection: 1; mode=block
// Referrer-Policy: strict-origin-when-cross-origin
// Content-Security-Policy: default-src 'self'Custom Security Headers
csharp
builder.Services.AddGrydAuth(options =>
{
options.SecurityHeaders.EnableHSTS = true;
options.SecurityHeaders.HSTSMaxAge = TimeSpan.FromDays(365);
options.SecurityHeaders.IncludeSubDomains = true;
options.SecurityHeaders.CustomHeaders = new Dictionary<string, string>
{
["Permissions-Policy"] = "geolocation=(), microphone=(), camera=()"
};
});Input Validation
Automatic Sanitization
csharp
builder.Services.AddGrydAuth(options =>
{
options.InputValidation.SanitizeHtml = true;
options.InputValidation.PreventSqlInjection = true;
options.InputValidation.MaxRequestBodySize = 1024 * 1024; // 1MB
});Request Validation
csharp
public class LoginRequestValidator : AbstractValidator<LoginRequest>
{
public LoginRequestValidator()
{
RuleFor(x => x.Email)
.NotEmpty()
.EmailAddress()
.MaximumLength(256);
RuleFor(x => x.Password)
.NotEmpty()
.MinimumLength(8)
.MaximumLength(128)
.Must(NotContainSqlInjection).WithMessage("Invalid characters detected");
}
private bool NotContainSqlInjection(string password)
{
var sqlPatterns = new[] { "'", "--", ";", "/*", "*/", "xp_" };
return !sqlPatterns.Any(p => password.Contains(p, StringComparison.OrdinalIgnoreCase));
}
}CORS Configuration
csharp
builder.Services.AddCors(options =>
{
options.AddPolicy("GrydAuthPolicy", policy =>
{
policy
.WithOrigins(
"https://yourapp.com",
"https://admin.yourapp.com"
)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
.SetPreflightMaxAge(TimeSpan.FromMinutes(10));
});
});
app.UseCors("GrydAuthPolicy");Encryption
Data Encryption
csharp
builder.Services.AddGrydAuth(options =>
{
options.Encryption.EncryptSensitiveData = true;
options.Encryption.Algorithm = EncryptionAlgorithm.AES256;
options.Encryption.KeyVaultUrl = Configuration["Azure:KeyVaultUrl"];
});Password Hashing
GrydAuth uses bcrypt for password hashing:
csharp
builder.Services.AddGrydAuth(options =>
{
options.PasswordHashing.Algorithm = HashingAlgorithm.BCrypt;
options.PasswordHashing.WorkFactor = 12; // Higher = more secure but slower
});Security Monitoring
Health Checks
csharp
builder.Services.AddHealthChecks()
.AddGrydAuthHealthChecks();
app.MapHealthChecks("/health", new HealthCheckOptions
{
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});Security Metrics
csharp
builder.Services.AddGrydAuth(options =>
{
options.Metrics.Enabled = true;
options.Metrics.Provider = MetricsProvider.Prometheus;
});
// Metrics exposed:
// gryd_auth_login_attempts_total
// gryd_auth_login_failures_total
// gryd_auth_tokens_issued_total
// gryd_auth_tokens_revoked_total
// gryd_auth_active_sessions_currentSecurity Checklist
Before going to production, ensure:
- [ ] JWT secret is stored in secure vault (not appsettings.json)
- [ ] HTTPS is enforced everywhere
- [ ] Rate limiting is enabled for auth endpoints
- [ ] Audit logging is enabled
- [ ] Password policy meets requirements
- [ ] Token expiration times are appropriate
- [ ] CORS is properly configured
- [ ] Security headers are enabled
- [ ] Database connections are encrypted (SSL/TLS)
- [ ] Sensitive data is encrypted at rest
- [ ] Regular security audits are scheduled