Skip to content

Authentication

GrydAuth provides a complete JWT-based authentication system with access and refresh tokens, password management, and secure session handling.

Token Types

Access Token

Short-lived token (default: 60 minutes) used for API authentication.

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Claims included:

  • sub - User ID
  • email - User email
  • name - Full name
  • roles - Assigned roles
  • permissions - Granted permissions
  • tenant_id - Tenant ID (if multi-tenant)
  • token_version - Token version for invalidation
  • scope - Token scope (tenant-selector-only for global tokens)
  • jti - JWT ID for token blacklisting

Refresh Token

Long-lived token (default: 7 days) used to obtain new access tokens without re-authentication.

Global vs Tenant Tokens

  • Global Token (2 minutes TTL): Restricted scope, used only for tenant selection when user has multiple tenants
  • Tenant Token (60 minutes TTL): Full access within a tenant context

Authentication Endpoints

Login

Authenticates a user and returns tokens.

http
POST /api/auth/login
Content-Type: application/json
X-App-Id: my-app-id

{
  "email": "user@example.com",
  "password": "Password123!",
  "isPasswordEncrypted": false,
  "preferredTenantId": "550e8400-e29b-41d4-a716-446655440001"
}

Success Response (200):

json
{
  "isSuccess": true,
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIs...",
    "refreshToken": "dGhpcyBpcyBhIHJlZnJlc2g...",
    "expiresAt": "2026-01-29T13:00:00Z",
    "permissions": ["read:products", "update:products"],
    "isFirstLogin": false,
    "mustChangePassword": false,
    "daysUntilPasswordExpiration": null,
    "isGlobal": false,
    "requiresTenantSelection": false,
    "tokenType": "Tenant",
    "currentTenant": {
      "id": "550e8400-e29b-41d4-a716-446655440001",
      "name": "Acme Corp",
      "isDefault": true,
      "permissions": ["read:products"]
    },
    "smartAutoSwitched": true
  }
}

Multi-Tenant Login

When the user has access to multiple tenants and no preferredTenantId is specified:

  • isGlobal: true - Token is a Global Token (2min TTL)
  • requiresTenantSelection: true - User must select a tenant
  • availableTenants - List of tenants the user can access
  • Use POST /api/auth/switch-tenant to get a full Tenant Token

Error Responses:

StatusCodeDescription
401INVALID_CREDENTIALSEmail or password is incorrect
401ACCOUNT_LOCKEDAccount is locked due to failed attempts
401EMAIL_NOT_CONFIRMEDEmail confirmation required
401ACCOUNT_DISABLEDAccount has been disabled

Register

Creates a new user account.

http
POST /api/auth/register
Content-Type: application/json

{
  "email": "newuser@example.com",
  "password": "SecurePass123!",
  "fullName": "Jane Doe",
  "phoneNumber": "+1234567890"
}

Success Response (201):

json
{
  "isSuccess": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "email": "newuser@example.com",
    "fullName": "Jane Doe",
    "createdAt": "2026-01-29T12:00:00Z"
  }
}

Refresh Token

Exchanges a valid refresh token for new tokens.

http
POST /api/auth/refresh
Content-Type: application/json

{
  "refreshToken": "dGhpcyBpcyBhIHJlZnJlc2g...",
  "tenantId": "550e8400-e29b-41d4-a716-446655440001"
}

Success Response (200):

json
{
  "isSuccess": true,
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIs...",
    "refreshToken": "bmV3IHJlZnJlc2ggdG9rZW4...",
    "expiresAt": "2026-01-29T14:00:00Z",
    "permissions": ["read:products"],
    "isGlobal": false,
    "tokenType": "Tenant"
  }
}

Refresh Token Rotation

GrydAuth uses refresh token rotation by default. Each refresh request issues a new refresh token and invalidates the previous one. This enhances security by limiting the window for token theft.

Logout

Invalidates the current session and all user tokens globally.

http
POST /api/auth/logout
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Simplified OAuth 2.0 Logout

GrydAuth follows OAuth 2.0 RFC 7009 best practices:

  • No request body required - All info extracted from Authorization header
  • Global logout - Invalidates ALL user sessions using timestamp-based blacklist
  • More secure - Doesn't expose refresh token in requests

For selective session management, consider implementing GET /api/auth/sessions in your application.

Password Management

Change Password

http
POST /api/auth/change-password
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json

{
  "currentPassword": "OldPassword123!",
  "newPassword": "NewSecurePass456!"
}

Forgot Password

Initiates password reset flow.

http
POST /api/auth/request-password-reset
Content-Type: application/json

{
  "email": "user@example.com"
}

This sends a password reset email with a token.

Reset Password

http
POST /api/auth/reset-password
Content-Type: application/json

{
  "email": "user@example.com",
  "token": "reset-token-from-email",
  "newPassword": "NewSecurePass789!"
}

Password Policy Configuration

Password policy is configured via appsettings.json:

json
{
  "PasswordPolicy": {
    "RequireDigit": true,
    "RequireLowercase": true,
    "RequireUppercase": true,
    "RequireNonAlphanumeric": true,
    "RequiredLength": 8,
    "RequiredUniqueChars": 4
  }
}

Account Lockout

Protect against brute-force attacks via appsettings.json:

json
{
  "Security": {
    "LockoutEnabled": true,
    "MaxFailedAccessAttempts": 5,
    "LockoutDurationMinutes": 15
  }
}

Token Versioning

GrydAuth supports token versioning for immediate invalidation:

csharp
// Invalidate all tokens for a user
await authService.InvalidateAllTokensAsync(userId);

// This increments the user's token version, making all existing tokens invalid

Scenarios that trigger token invalidation:

  1. Password change
  2. Security settings change
  3. Role/permission update
  4. Manual logout from all devices
  5. Admin-triggered invalidation

Using Authentication in Code

Injecting Current User

csharp
using GrydAuth.Application.Common.Interfaces;

public class ProductService
{
    private readonly ICurrentUserService _currentUser;
    
    public ProductService(ICurrentUserService currentUser)
    {
        _currentUser = currentUser;
    }
    
    public async Task<Product> CreateAsync(CreateProductRequest request)
    {
        var product = new Product
        {
            Name = request.Name,
            CreatedBy = _currentUser.UserId, // Get current user ID
            TenantId = _currentUser.TenantId // Get current tenant
        };
        
        // ...
    }
}

ICurrentUserService Properties

PropertyTypeDescription
UserIdGuid?Current user's ID
Emailstring?Current user's email
FullNamestring?Current user's full name
TenantIdGuid?Current tenant ID
RolesIEnumerable<string>User's roles
PermissionsIEnumerable<string>User's permissions
IsAuthenticatedboolWhether user is authenticated

Custom Claims

Add custom claims to tokens:

csharp
public class CustomClaimsService : ICustomClaimsProvider
{
    private readonly IUserService _userService;
    
    public async Task<IEnumerable<Claim>> GetClaimsAsync(User user)
    {
        var department = await _userService.GetDepartmentAsync(user.Id);
        
        return new[]
        {
            new Claim("department", department.Name),
            new Claim("department_id", department.Id.ToString())
        };
    }
}

// Register in DI
builder.Services.AddScoped<ICustomClaimsProvider, CustomClaimsService>();

Two-Factor Authentication (2FA)

Coming Soon

Two-factor authentication support is planned for GrydAuth v1.1.0

External Authentication

Social Login

GrydAuth supports social login via POST /api/auth/social-login:

http
POST /api/auth/social-login
Content-Type: application/json
X-App-Id: my-app-id

{
  "provider": "google",
  "accessToken": "ya29.a0AfH6SM...",
  "preferredTenantId": "550e8400-e29b-41d4-a716-446655440001"
}

Supported providers depend on your Auth0 or custom OAuth configuration.

Auth0 Integration

Install the Auth0 package:

bash
dotnet add package GrydAuth.Infrastructure.Auth0

Configure in appsettings.json:

json
{
  "Auth0": {
    "Domain": "your-tenant.auth0.com",
    "ClientId": "your-client-id",
    "ClientSecret": "your-client-secret",
    "Audience": "https://your-api.com"
  }
}

Security Best Practices

  1. Use HTTPS - Always use HTTPS in production
  2. Secure Secret Key - Store JWT secret in secure vault (Azure Key Vault, AWS Secrets Manager)
  3. Short Token Lifetime - Keep access tokens short-lived (15-60 minutes)
  4. Refresh Token Rotation - Enable refresh token rotation (default)
  5. Token Versioning - Enable token versioning for immediate invalidation
  6. Rate Limiting - Configure rate limiting for auth endpoints
  7. Audit Logging - Enable audit logging for authentication events

Released under the MIT License.