Appearance
Getting Started with GrydAuth
This guide will walk you through setting up GrydAuth in your .NET application from scratch.
Prerequisites
- .NET 10.0 SDK or later
- PostgreSQL, SQL Server, or any EF Core compatible database
- Basic understanding of ASP.NET Core authentication
Step 1: Create a New Project
bash
# Create new Web API project
dotnet new webapi -n MyApp.API -o src/MyApp.API
# Create class libraries for Clean Architecture
dotnet new classlib -n MyApp.Domain -o src/MyApp.Domain
dotnet new classlib -n MyApp.Application -o src/MyApp.Application
dotnet new classlib -n MyApp.Infrastructure -o src/MyApp.Infrastructure
# Add to solution
dotnet new sln -n MyApp
dotnet sln add src/MyApp.API
dotnet sln add src/MyApp.Domain
dotnet sln add src/MyApp.Application
dotnet sln add src/MyApp.InfrastructureStep 2: Install GrydAuth Packages
bash
# Core packages
cd src/MyApp.Domain
dotnet add package GrydAuth.Domain
cd ../MyApp.Application
dotnet add package GrydAuth.Application
cd ../MyApp.Infrastructure
dotnet add package GrydAuth.Infrastructure
cd ../MyApp.API
dotnet add package GrydAuth.API
dotnet add package GrydAuth.InfrastructureStep 3: Configure Database Context
Create your DbContext that extends GrydAuthDbContext:
csharp
// src/MyApp.Infrastructure/Data/AppDbContext.cs
using GrydAuth.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
namespace MyApp.Infrastructure.Data;
public class AppDbContext : GrydAuthDbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
// Add your custom DbSets here
// public DbSet<Product> Products => Set<Product>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Your custom entity configurations
// modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
}
}Step 4: Configure Program.cs
csharp
// src/MyApp.API/Program.cs
using GrydAuth.API.Controllers;
using GrydAuth.Infrastructure;
using Gryd.API.Extensions;
using MyApp.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// 1. Add GrydAuth services (Application + Infrastructure + JWT + Authorization)
// All configuration is read from appsettings.json sections
builder.Services.AddGrydAuth(builder.Configuration);
// 2. Add Controllers (includes GrydAuth API controllers)
builder.Services.AddControllers()
.AddApplicationPart(typeof(AuthController).Assembly);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// 3. Configure Database
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
// 4. Add Exception Handlers (IExceptionHandler pipeline - .NET 8+)
// IMPORTANT: Register in order of specificity (most specific first)
builder.Services.AddGrydAuthExceptionHandler(); // GrydAuth-specific (Redis, DB, etc.)
builder.Services.AddCoreExceptionHandler(); // Core fallback (validation, security, etc.)
var app = builder.Build();
// Configure pipeline
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
// CRITICAL: Exception handling MUST be first to catch all exceptions
app.UseExceptionHandler();
app.UseHttpsRedirection();
app.UseRouting();
// Authentication (standard ASP.NET Core)
app.UseAuthentication();
// GrydAuth middleware (token blacklist, SmartFederation, AppId validation)
// CRITICAL: Must be AFTER Authentication but BEFORE Authorization
app.UseGrydAuth();
// Authorization (standard ASP.NET Core)
app.UseAuthorization();
app.MapControllers();
app.Run();Step 5: Configure appsettings.json
All GrydAuth configuration is consolidated under the GrydAuth section for better organization:
json
{
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Database=myapp;Username=postgres;Password=your_password"
},
"JwtSettings": {
"SecretKey": "your-super-secret-key-at-least-256-bits-long-for-security",
"Issuer": "myapp",
"Audience": "myapp-users",
"ExpirationMinutes": 60,
"RefreshTokenExpirationDays": 7,
"AppId": "my-app-id"
},
"GrydAuth": {
"SmartFederation": {
"IsEnabled": true,
"CacheFirst": true,
"PerformanceHeaders": true,
"TokenCacheMinutes": 15,
"UserClaimsCacheMinutes": 30,
"DatabaseFallback": true
},
"Cache": {
"IsEnabled": true,
"DefaultExpirationMinutes": 15,
"TokenCacheMinutes": 15,
"UserClaimsCacheMinutes": 30,
"Redis": {
"ConnectionString": "localhost:6379",
"Database": 0,
"KeyPrefix": "MyApp:",
"Compression": true
}
},
"Storage": {
"AwsS3": {
"BucketName": "",
"Region": "us-east-1",
"AccessKeyId": "",
"SecretAccessKey": "",
"ProfilePicturesPrefix": "profile-pictures/",
"MaxFileSizeBytes": 5242880,
"AllowedContentTypes": ["image/jpeg", "image/png", "image/gif", "image/webp"]
}
},
"PasswordPolicy": {
"MinLength": 8,
"RequireUppercase": true,
"RequireLowercase": true,
"RequireDigit": true,
"RequireSpecialChar": true,
"SpecialCharacters": "!@#$%^&*()_+-=[]{}|;':\",./<>?",
"MaxLength": 128,
"EnablePasswordExpiration": true,
"ExpirationDays": 90,
"WarnBeforeExpirationDays": 7,
"EnablePasswordHistory": false,
"PasswordHistoryCount": 5
},
"PasswordReset": {
"TokenExpirationMinutes": 60,
"BaseUrl": "https://yourapp.com",
"ResetPath": "/reset-password",
"FromEmail": "noreply@yourapp.com",
"FromName": "Your App"
},
"Security": {
"MaxFailedAccessAttempts": 5,
"LockoutDurationMinutes": 15,
"EnableSecurityLogging": true
},
"Email": {
"Provider": "Smtp",
"SmtpHost": "smtp.yourprovider.com",
"SmtpPort": 587,
"SmtpUsername": "",
"SmtpPassword": "",
"UseSsl": true
},
"CircuitBreaker": {
"FailureThreshold": 5,
"SamplingDurationSeconds": 30,
"MinimumThroughput": 10,
"DurationOfBreakSeconds": 60
},
"GeoIp": {
"Provider": "MaxMind",
"MaxMindDatabasePath": "GeoLite2-City.mmdb",
"MaxMindAccountId": 0,
"MaxMindLicenseKey": "",
"EnableAutomaticUpdates": false,
"UpdateIntervalDays": 7
},
"ImpossibleTravel": {
"MaxVelocityKmh": 900.0,
"TimeWindowMinutes": 60,
"MinimumDistanceKm": 10.0,
"AutoBlockCriticalRisk": false,
"NotifySecurityTeam": true
}
},
"MultiTenancy": {
"IsEnabled": true,
"Strategy": "Header",
"TenantHeaderName": "X-Tenant-ID",
"TenantQueryParameter": "tenantId",
"TenantRouteParameter": "tenantId",
"DefaultTenantId": "",
"Tenants": []
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}Configuration Sections
All GrydAuth configuration is consolidated under the GrydAuth section:
- GrydAuth:SmartFederation - Cache-first authentication strategy
- GrydAuth:Cache - Redis cache configuration for token blacklisting
- GrydAuth:Storage - File storage (AWS S3 for profile pictures)
- GrydAuth:PasswordPolicy - Password complexity requirements
- GrydAuth:PasswordReset - Password reset token settings
- GrydAuth:Security - Account lockout and security settings
- GrydAuth:Email - Email service configuration
- GrydAuth:CircuitBreaker - Smart Federation resilience settings
- GrydAuth:GeoIp - GeoIP/MaxMind configuration
- GrydAuth:ImpossibleTravel - Travel velocity anomaly detection External configuration:
- JwtSettings - JWT token configuration (SecretKey, Issuer, Audience, etc.)
- MultiTenancy - Multi-tenant mode settings (Core feature, not GrydAuth-specific)
Step 6: Run Your Application
In Development environment, GrydAuth migrations are applied automatically when the application starts:
bash
cd src/MyApp.API
dotnet run✅ The
ApplyGrydAuthMigrationsAsync()method applies pending migrations automatically.
Update Admin User AppId (Required - First Run)
After the first run, update the admin user's AppId to match your appsettings.Development.json:
sql
-- Find your AppId in JwtSettings.AppId and update:
UPDATE public."UserAppIds"
SET "AppId" = 'MyApp-dev-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
WHERE "UserId" = '11111111-1111-1111-1111-111111111111';⚠️ Without this step, login will fail with:
Invalid application ID
Step 7: Create Your First User
GrydAuth provides built-in endpoints for user management. Once your application is running:
Register a User
bash
POST /api/v1/auth/register
Content-Type: application/json
{
"email": "admin@example.com",
"password": "Admin@123!",
"fullName": "System Administrator"
}Login
bash
POST /api/v1/auth/login
Content-Type: application/json
X-App-Id: my-app-id
{
"email": "admin@example.com",
"password": "Admin@123!",
"isPasswordEncrypted": false
}Response:
json
{
"isSuccess": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...",
"expiresAt": "2026-01-29T13:00:00Z",
"permissions": ["read:users", "update:users"],
"isFirstLogin": false,
"mustChangePassword": false,
"isGlobal": false,
"requiresTenantSelection": false,
"tokenType": "Tenant",
"currentTenant": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "Default Tenant",
"isDefault": true
}
}
}Multi-Tenant Authentication
When multi-tenancy is enabled and the user has access to multiple tenants:
- First login returns a Global Token (2min TTL,
isGlobal: true) - Use
POST /api/v1/auth/switch-tenantwith the target tenant ID - You'll receive a Tenant Token (60min TTL) with full access
Use the Token
bash
GET /api/v1/auth/me
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...Response (basic info from JWT):
json
{
"isSuccess": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "System Administrator",
"email": "admin@example.com",
"roles": ["Admin"],
"permissions": ["read:users", "update:users"]
}
}Complete profile (from database):
bash
GET /api/v1/auth/me/completeStep 8: Protect Your Endpoints
Using Built-in Attributes
csharp
using GrydAuth.API.Attributes;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
[Authorize] // Requires authentication
public class ProductsController : ControllerBase
{
// Anyone authenticated can read
[HttpGet]
[RequirePermission("read:products")]
public IActionResult GetAll() => Ok(new[] { "Product 1", "Product 2" });
// Only users with create permission
[HttpPost]
[RequirePermission("create:products")]
public IActionResult Create([FromBody] CreateProductRequest request)
=> Created("", new { Id = Guid.NewGuid() });
// Only admins
[HttpDelete("{id}")]
[Authorize(Roles = "Admin")]
public IActionResult Delete(Guid id) => NoContent();
}Using Policy-Based Authorization
csharp
// Program.cs
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("CanManageUsers", policy =>
policy.RequirePermission("create:users", "update:users", "delete:users"));
options.AddPolicy("AdminOnly", policy =>
policy.RequireRole("Admin", "SuperAdmin"));
});
// Controller
[HttpPost]
[Authorize(Policy = "CanManageUsers")]
public IActionResult CreateUser([FromBody] CreateUserRequest request) { ... }Next Steps
Now that you have GrydAuth set up, explore these topics:
- Authentication - Deep dive into JWT tokens and login flows
- Authorization - Configure roles and permissions
- Multi-Tenancy - Set up tenant isolation
- Security Features - Rate limiting, audit logging, and more
- Auth Endpoints - Authentication, preferences, and menu favorites
- CRUD Endpoints - Users, roles, permissions, tenants, security
Common Issues
Token Validation Fails
Ensure your SecretKey is at least 256 bits (32 characters) and consistent across all environments.
CORS Issues
Add CORS configuration before authentication middleware:
csharp
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.WithOrigins("http://localhost:3000")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
// In pipeline (before UseAuthentication)
app.UseCors();Database Connection
Ensure your connection string is correct and the database exists. PostgreSQL example:
bash
# Create database
psql -U postgres -c "CREATE DATABASE myapp;"