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/auth/register
Content-Type: application/json
{
"email": "admin@example.com",
"password": "Admin@123!",
"fullName": "System Administrator"
}Login
bash
POST /api/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/auth/switch-tenantwith the target tenant ID - You'll receive a Tenant Token (60min TTL) with full access
Use the Token
bash
GET /api/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 (with include=profile):
bash
GET /api/auth/me?include=profile
# or
GET /api/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
- API Reference - Complete endpoint documentation
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;"