Skip to content

feat(frontend): move all system routes to /system/* prefix#39

Merged
juljanblischke merged 6 commits into
mainfrom
feat/system-routes-prefix
Jan 19, 2026
Merged

feat(frontend): move all system routes to /system/* prefix#39
juljanblischke merged 6 commits into
mainfrom
feat/system-routes-prefix

Conversation

@juljanblischke

Copy link
Copy Markdown
Owner

Description

Move all system admin routes under /system/* prefix to prepare for Pro's deployment mode feature (self-hosted vs SaaS routing).

Related Issue

Part of Task 028: Frontend Pro Setup - Routing Architecture

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to change)
  • 📚 Documentation update
  • 🔧 Configuration change
  • ♻️ Refactoring (no functional changes)
  • 🧪 Test update

Changes Made

  • Update __root.tsx with /system/* prefixed routes
  • Update navigation.ts hrefs to /system/*
  • Update index-page.tsx redirect to /system/login or /system/dashboard
  • Rename Dashboard to System Dashboard in i18n (en/de)
  • Update auth-context.tsx redirect paths
  • Fix breadcrumbs to filter out /system prefix
  • Update all hardcoded paths in components and hooks

Screenshots

N/A - routing change only

Testing

  • Unit tests pass locally
  • Integration tests pass locally
  • Manual testing completed

Test Instructions

  1. Navigate to / - should redirect to /system/login
  2. Login - should redirect to /system/dashboard
  3. Check all navigation links work with /system/* prefix
  4. Verify breadcrumbs show correctly (no "system" segment)

Checklist

  • My code follows the project's code style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

Additional Notes

This is preparation for Pro's deployment mode feature where system routes (/system/*) are separate from customer routes (/customer/*).

juljanblischke and others added 6 commits January 18, 2026 19:19
Added generic error message for captcha verification failures in both
EN and DE locales.
- Add missing `auth:captcha.error` translation key in EN and DE auth.json
- Add protected constructor to AppDbContext for DbContext inheritance support
  (required by Pro's ProDbContext which extends AppDbContext)
fix: add captcha.error translation and protected DbContext constructor
* Create MagicLinkToken entity with token generation

Created MagicLinkToken entity for passwordless authentication following
PasswordResetToken pattern:
- Token generation using cryptographically secure random bytes (32 bytes)
- SHA256 hashing for secure token storage
- 15-minute expiration window (configurable)
- Single-use validation with IsUsed/UsedAt tracking
- Token validation against stored hash
- Inherits from BaseEntity for standard Id/CreatedAt/UpdatedAt fields

Simplified compared to PasswordResetToken (removed code-based auth).

* Add MagicLinkToken EF Core configuration

* Add DbSet<MagicLinkToken> to IAppDbContext and AppDbContext

* Create and apply EF Core migration for MagicLinkToken

* Create IMagicLinkService interface

* Implement MagicLinkService with collision prevention

Implemented MagicLinkService following PasswordResetService pattern:
- CreateMagicLinkAsync with collision prevention (3 retries)
- ValidateTokenAsync for token validation
- MarkAsUsedAsync for single-use enforcement
- InvalidateAllTokensAsync for user token invalidation
- SHA256 token hashing for secure comparison
- 15-minute expiration (configurable via Auth:MagicLinkExpiryMinutes)
- Comprehensive logging via ILogger

Build verified: 0 errors, 0 warnings

* Register IMagicLinkService in DI container

* Create RequestMagicLink command, handler, and validator

Created RequestMagicLink CQRS command with handler and validator following ForgotPassword pattern:
- RequestMagicLinkCommand: Command with email, captchaToken, ipAddress parameters
- RequestMagicLinkHandler: Handler with captcha validation, user lookup, token creation, email sending, audit logging, anti-enumeration response
- RequestMagicLinkValidator: FluentValidation validator for email format
- Added MagicLinkRequested, MagicLinkLogin, MagicLinkLoginFailed audit actions to AuditActions
- Added SendMagicLinkAsync method to IEmailService and EmailService implementation
- Handler validates CAPTCHA, checks user exists/active/not-anonymized, creates magic link token, sends email, logs audit event
- Always returns success response to prevent email enumeration
- Build verified: 0 errors, 0 warnings

* Create LoginWithMagicLink command, handler, and validator

- Created LoginWithMagicLinkCommand with token and device info parameters
- Created LoginWithMagicLinkValidator for token validation
- Created LoginWithMagicLinkHandler with full authentication flow:
  * Validates magic link token via IMagicLinkService
  * Marks token as used after validation
  * Handles MFA if enabled (returns RequiresMfa response)
  * Handles MFA setup requirement for system permission users
  * Device tracking and risk scoring (new device approval flow)
  * Spoofing detection for trusted devices
  * Session creation with access and refresh tokens
  * Login pattern recording for risk analysis
  * Comprehensive audit logging
  * New location email notification
- Added MagicLinkTokenInvalidException to AuthException.cs
- Handler follows LoginHandler pattern for consistency
- Build verified successfully with 0 errors/warnings

* Create magic link email templates (English and German)

* Add email template subjects for magic link

Added magic-link subjects to both English and German subjects.json files:
- English: 'Your magic link to sign in'
- German: 'Ihr Magic Link zum Anmelden'

Note: Task spec indicated modifying EmailTemplateService.cs, but the correct
approach is to add subjects to subjects.json files, which EmailTemplateService
loads dynamically.

* Add POST /api/system/auth/magic-link/request endpoint

* Add POST /api/system/auth/magic-link/login endpoint

* Create MagicLinkForm component for requesting magic link

Created MagicLinkForm component following accept-invite-form pattern with:
- Email input field with validation
- CAPTCHA widget integration
- Submit button with loading states
- Error message display
- react-hook-form + zod validation
- useRequestMagicLink hook

Also added supporting code to make component compile:
- RequestMagicLinkRequest/Response types in @/types/auth
- requestMagicLink API function in auth-api.ts
- useRequestMagicLink hook
- createMagicLinkSchema and MagicLinkFormData in types/index.ts

Build verified successfully.

* Create MagicLinkSent component for confirmation sc

* Add magic link API functions to auth-api.ts

- Added MagicLinkLoginRequest type extending DeviceInfo with token and rememberMe fields
- Added magicLinkLogin function to authApi for /system/auth/magic-link/login endpoint
- Follows pattern from password-reset-api.ts with async/await and extractData helper
- Returns AuthResponse for authentication flow completion

* Create React hooks for magic link flow

Created useMagicLinkLogin hook following the useLogin pattern. The hook:
- Uses useMutation from react-query for API calls
- Handles MFA requirements (verification and setup)
- Handles device approval flow for risk-based authentication
- Updates auth state and navigates on successful login
- Provides callback options for different auth flows

Also exported both useRequestMagicLink and useMagicLinkLogin from the
hooks index for easy consumption.

Build verified successfully.

* Create /magic-link-login route for token validation

* Add 'Sign in with magic link' option to login page

- Export MagicLinkForm and MagicLinkSent from auth components
- Add toggle between password and magic link login modes
- Implement state management for login mode switching
- Show MagicLinkSent component after successful magic link request
- Add translation keys for toggle buttons (useMagicLink, usePassword)
- Add missing magicLink translation keys (email, button, sending, sent, sentMessage)

* Add i18n translations for magic link feature

* End-to-end magic link flow verification

Verified magic link passwordless login functionality:

✅ API Endpoints:
- POST /api/system/auth/magic-link/request returns 200
- Token generation and storage working
- Anti-enumeration implemented
- Rate limiting applied
- Audit logging functional

✅ Database:
- magic_link_tokens table operational
- Token hashing (SHA256) verified
- 15-minute expiration configured
- Single-use enforcement via is_used column
- Previous tokens auto-invalidated

✅ Security Features:
- Cryptographically secure tokens (32 bytes)
- Collision prevention (3 retries)
- CAPTCHA integration (configurable)
- Rate limiting on sensitive endpoints

✅ Frontend:
- MagicLinkForm component built
- Login page integration complete
- /magic-link-login route created
- Translations (EN/DE) added
- React hooks implemented

✅ Email Templates:
- Templates created (en-US, de-DE)
- Subjects configured in subjects.json
- Variables properly defined

⚠️ Email Worker Note:
Email worker has environment configuration issue preventing
actual SMTP sending. This is a deployment concern, not a code
issue. Emails are correctly queued to RabbitMQ.

Services tested:
- Backend API (port 5096) ✅
- Frontend (port 5176) ✅
- PostgreSQL ✅
- RabbitMQ ✅
- MailHog ✅

Test results documented in:
- .specs/002-magic-link-passwordless-login/e2e-test-results.md
- backend/test-magic-link.md

All magic link feature code is complete and functional.

* Update API documentation with magic link endpoints

- Enabled XML documentation generation in ExoAuth.Api.csproj
- Configured Swagger to include XML comments from generated documentation file
- Magic link endpoints now documented in Swagger/OpenAPI with:
  * POST /api/system/auth/magic-link/request - Request magic link email
  * POST /api/system/auth/magic-link/login - Login with magic link token
- Both endpoints include proper summaries, request/response schemas, and status codes
- Added swagger-verification.md with verification steps

* Add unit tests for magic link feature

- Add MagicLinkToken entity tests (token creation, hashing, expiration, validation)
- Add RequestMagicLinkHandler tests (email handling, CAPTCHA, user states)
- Add LoginWithMagicLinkHandler tests (auth flow, MFA, device approval)
- Add validator tests for RequestMagicLink and LoginWithMagicLink commands
- Update TestDataFactory with MagicLinkToken helpers
- Update MockDbContext with MagicLinkTokens DbSet

* fix: check siteKey in captchaRequired to prevent disabled button

* fix: back to login button on magic link sent page

* chore: remove deprecated Email section from appsettings

Email configuration is now database-driven (Task 025/026).
The old static Email section in appsettings is no longer used.

* ci: add develop branch to CI workflow triggers

* fix: remove BOM from migration file

---------

Co-authored-by: jxljan <juljan.blischke@gmail.com>
- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture
@juljanblischke juljanblischke merged commit c0e2b9f into main Jan 19, 2026
2 checks passed
juljanblischke added a commit that referenced this pull request Jan 20, 2026
juljanblischke added a commit that referenced this pull request Jan 20, 2026
juljanblischke added a commit that referenced this pull request Jan 20, 2026
* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

* feat(frontend): move all system routes to /system/* prefix (#39)

* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* fix: add captcha.error translation and protected DbContext constructor

- Add missing `auth:captcha.error` translation key in EN and DE auth.json
- Add protected constructor to AppDbContext for DbContext inheritance support
  (required by Pro's ProDbContext which extends AppDbContext)

* Add Magic Link Passwordless Login Feature (#38)

* Create MagicLinkToken entity with token generation

Created MagicLinkToken entity for passwordless authentication following
PasswordResetToken pattern:
- Token generation using cryptographically secure random bytes (32 bytes)
- SHA256 hashing for secure token storage
- 15-minute expiration window (configurable)
- Single-use validation with IsUsed/UsedAt tracking
- Token validation against stored hash
- Inherits from BaseEntity for standard Id/CreatedAt/UpdatedAt fields

Simplified compared to PasswordResetToken (removed code-based auth).

* Add MagicLinkToken EF Core configuration

* Add DbSet<MagicLinkToken> to IAppDbContext and AppDbContext

* Create and apply EF Core migration for MagicLinkToken

* Create IMagicLinkService interface

* Implement MagicLinkService with collision prevention

Implemented MagicLinkService following PasswordResetService pattern:
- CreateMagicLinkAsync with collision prevention (3 retries)
- ValidateTokenAsync for token validation
- MarkAsUsedAsync for single-use enforcement
- InvalidateAllTokensAsync for user token invalidation
- SHA256 token hashing for secure comparison
- 15-minute expiration (configurable via Auth:MagicLinkExpiryMinutes)
- Comprehensive logging via ILogger

Build verified: 0 errors, 0 warnings

* Register IMagicLinkService in DI container

* Create RequestMagicLink command, handler, and validator

Created RequestMagicLink CQRS command with handler and validator following ForgotPassword pattern:
- RequestMagicLinkCommand: Command with email, captchaToken, ipAddress parameters
- RequestMagicLinkHandler: Handler with captcha validation, user lookup, token creation, email sending, audit logging, anti-enumeration response
- RequestMagicLinkValidator: FluentValidation validator for email format
- Added MagicLinkRequested, MagicLinkLogin, MagicLinkLoginFailed audit actions to AuditActions
- Added SendMagicLinkAsync method to IEmailService and EmailService implementation
- Handler validates CAPTCHA, checks user exists/active/not-anonymized, creates magic link token, sends email, logs audit event
- Always returns success response to prevent email enumeration
- Build verified: 0 errors, 0 warnings

* Create LoginWithMagicLink command, handler, and validator

- Created LoginWithMagicLinkCommand with token and device info parameters
- Created LoginWithMagicLinkValidator for token validation
- Created LoginWithMagicLinkHandler with full authentication flow:
  * Validates magic link token via IMagicLinkService
  * Marks token as used after validation
  * Handles MFA if enabled (returns RequiresMfa response)
  * Handles MFA setup requirement for system permission users
  * Device tracking and risk scoring (new device approval flow)
  * Spoofing detection for trusted devices
  * Session creation with access and refresh tokens
  * Login pattern recording for risk analysis
  * Comprehensive audit logging
  * New location email notification
- Added MagicLinkTokenInvalidException to AuthException.cs
- Handler follows LoginHandler pattern for consistency
- Build verified successfully with 0 errors/warnings

* Create magic link email templates (English and German)

* Add email template subjects for magic link

Added magic-link subjects to both English and German subjects.json files:
- English: 'Your magic link to sign in'
- German: 'Ihr Magic Link zum Anmelden'

Note: Task spec indicated modifying EmailTemplateService.cs, but the correct
approach is to add subjects to subjects.json files, which EmailTemplateService
loads dynamically.

* Add POST /api/system/auth/magic-link/request endpoint

* Add POST /api/system/auth/magic-link/login endpoint

* Create MagicLinkForm component for requesting magic link

Created MagicLinkForm component following accept-invite-form pattern with:
- Email input field with validation
- CAPTCHA widget integration
- Submit button with loading states
- Error message display
- react-hook-form + zod validation
- useRequestMagicLink hook

Also added supporting code to make component compile:
- RequestMagicLinkRequest/Response types in @/types/auth
- requestMagicLink API function in auth-api.ts
- useRequestMagicLink hook
- createMagicLinkSchema and MagicLinkFormData in types/index.ts

Build verified successfully.

* Create MagicLinkSent component for confirmation sc

* Add magic link API functions to auth-api.ts

- Added MagicLinkLoginRequest type extending DeviceInfo with token and rememberMe fields
- Added magicLinkLogin function to authApi for /system/auth/magic-link/login endpoint
- Follows pattern from password-reset-api.ts with async/await and extractData helper
- Returns AuthResponse for authentication flow completion

* Create React hooks for magic link flow

Created useMagicLinkLogin hook following the useLogin pattern. The hook:
- Uses useMutation from react-query for API calls
- Handles MFA requirements (verification and setup)
- Handles device approval flow for risk-based authentication
- Updates auth state and navigates on successful login
- Provides callback options for different auth flows

Also exported both useRequestMagicLink and useMagicLinkLogin from the
hooks index for easy consumption.

Build verified successfully.

* Create /magic-link-login route for token validation

* Add 'Sign in with magic link' option to login page

- Export MagicLinkForm and MagicLinkSent from auth components
- Add toggle between password and magic link login modes
- Implement state management for login mode switching
- Show MagicLinkSent component after successful magic link request
- Add translation keys for toggle buttons (useMagicLink, usePassword)
- Add missing magicLink translation keys (email, button, sending, sent, sentMessage)

* Add i18n translations for magic link feature

* End-to-end magic link flow verification

Verified magic link passwordless login functionality:

✅ API Endpoints:
- POST /api/system/auth/magic-link/request returns 200
- Token generation and storage working
- Anti-enumeration implemented
- Rate limiting applied
- Audit logging functional

✅ Database:
- magic_link_tokens table operational
- Token hashing (SHA256) verified
- 15-minute expiration configured
- Single-use enforcement via is_used column
- Previous tokens auto-invalidated

✅ Security Features:
- Cryptographically secure tokens (32 bytes)
- Collision prevention (3 retries)
- CAPTCHA integration (configurable)
- Rate limiting on sensitive endpoints

✅ Frontend:
- MagicLinkForm component built
- Login page integration complete
- /magic-link-login route created
- Translations (EN/DE) added
- React hooks implemented

✅ Email Templates:
- Templates created (en-US, de-DE)
- Subjects configured in subjects.json
- Variables properly defined

⚠️ Email Worker Note:
Email worker has environment configuration issue preventing
actual SMTP sending. This is a deployment concern, not a code
issue. Emails are correctly queued to RabbitMQ.

Services tested:
- Backend API (port 5096) ✅
- Frontend (port 5176) ✅
- PostgreSQL ✅
- RabbitMQ ✅
- MailHog ✅

Test results documented in:
- .specs/002-magic-link-passwordless-login/e2e-test-results.md
- backend/test-magic-link.md

All magic link feature code is complete and functional.

* Update API documentation with magic link endpoints

- Enabled XML documentation generation in ExoAuth.Api.csproj
- Configured Swagger to include XML comments from generated documentation file
- Magic link endpoints now documented in Swagger/OpenAPI with:
  * POST /api/system/auth/magic-link/request - Request magic link email
  * POST /api/system/auth/magic-link/login - Login with magic link token
- Both endpoints include proper summaries, request/response schemas, and status codes
- Added swagger-verification.md with verification steps

* Add unit tests for magic link feature

- Add MagicLinkToken entity tests (token creation, hashing, expiration, validation)
- Add RequestMagicLinkHandler tests (email handling, CAPTCHA, user states)
- Add LoginWithMagicLinkHandler tests (auth flow, MFA, device approval)
- Add validator tests for RequestMagicLink and LoginWithMagicLink commands
- Update TestDataFactory with MagicLinkToken helpers
- Update MockDbContext with MagicLinkTokens DbSet

* fix: check siteKey in captchaRequired to prevent disabled button

* fix: back to login button on magic link sent page

* chore: remove deprecated Email section from appsettings

Email configuration is now database-driven (Task 025/026).
The old static Email section in appsettings is no longer used.

* ci: add develop branch to CI workflow triggers

* fix: remove BOM from migration file

---------

Co-authored-by: jxljan <juljan.blischke@gmail.com>

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

* Revert "feat(frontend): move all system routes to /system/* prefix (#39)" (#40)

This reverts commit c0e2b9f.

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>
@juljanblischke juljanblischke deleted the feat/system-routes-prefix branch January 20, 2026 12:03
juljanblischke added a commit that referenced this pull request Jan 20, 2026
* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

* feat(frontend): move all system routes to /system/* prefix (#39)

* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* fix: add captcha.error translation and protected DbContext constructor

- Add missing `auth:captcha.error` translation key in EN and DE auth.json
- Add protected constructor to AppDbContext for DbContext inheritance support
  (required by Pro's ProDbContext which extends AppDbContext)

* Add Magic Link Passwordless Login Feature (#38)

* Create MagicLinkToken entity with token generation

Created MagicLinkToken entity for passwordless authentication following
PasswordResetToken pattern:
- Token generation using cryptographically secure random bytes (32 bytes)
- SHA256 hashing for secure token storage
- 15-minute expiration window (configurable)
- Single-use validation with IsUsed/UsedAt tracking
- Token validation against stored hash
- Inherits from BaseEntity for standard Id/CreatedAt/UpdatedAt fields

Simplified compared to PasswordResetToken (removed code-based auth).

* Add MagicLinkToken EF Core configuration

* Add DbSet<MagicLinkToken> to IAppDbContext and AppDbContext

* Create and apply EF Core migration for MagicLinkToken

* Create IMagicLinkService interface

* Implement MagicLinkService with collision prevention

Implemented MagicLinkService following PasswordResetService pattern:
- CreateMagicLinkAsync with collision prevention (3 retries)
- ValidateTokenAsync for token validation
- MarkAsUsedAsync for single-use enforcement
- InvalidateAllTokensAsync for user token invalidation
- SHA256 token hashing for secure comparison
- 15-minute expiration (configurable via Auth:MagicLinkExpiryMinutes)
- Comprehensive logging via ILogger

Build verified: 0 errors, 0 warnings

* Register IMagicLinkService in DI container

* Create RequestMagicLink command, handler, and validator

Created RequestMagicLink CQRS command with handler and validator following ForgotPassword pattern:
- RequestMagicLinkCommand: Command with email, captchaToken, ipAddress parameters
- RequestMagicLinkHandler: Handler with captcha validation, user lookup, token creation, email sending, audit logging, anti-enumeration response
- RequestMagicLinkValidator: FluentValidation validator for email format
- Added MagicLinkRequested, MagicLinkLogin, MagicLinkLoginFailed audit actions to AuditActions
- Added SendMagicLinkAsync method to IEmailService and EmailService implementation
- Handler validates CAPTCHA, checks user exists/active/not-anonymized, creates magic link token, sends email, logs audit event
- Always returns success response to prevent email enumeration
- Build verified: 0 errors, 0 warnings

* Create LoginWithMagicLink command, handler, and validator

- Created LoginWithMagicLinkCommand with token and device info parameters
- Created LoginWithMagicLinkValidator for token validation
- Created LoginWithMagicLinkHandler with full authentication flow:
  * Validates magic link token via IMagicLinkService
  * Marks token as used after validation
  * Handles MFA if enabled (returns RequiresMfa response)
  * Handles MFA setup requirement for system permission users
  * Device tracking and risk scoring (new device approval flow)
  * Spoofing detection for trusted devices
  * Session creation with access and refresh tokens
  * Login pattern recording for risk analysis
  * Comprehensive audit logging
  * New location email notification
- Added MagicLinkTokenInvalidException to AuthException.cs
- Handler follows LoginHandler pattern for consistency
- Build verified successfully with 0 errors/warnings

* Create magic link email templates (English and German)

* Add email template subjects for magic link

Added magic-link subjects to both English and German subjects.json files:
- English: 'Your magic link to sign in'
- German: 'Ihr Magic Link zum Anmelden'

Note: Task spec indicated modifying EmailTemplateService.cs, but the correct
approach is to add subjects to subjects.json files, which EmailTemplateService
loads dynamically.

* Add POST /api/system/auth/magic-link/request endpoint

* Add POST /api/system/auth/magic-link/login endpoint

* Create MagicLinkForm component for requesting magic link

Created MagicLinkForm component following accept-invite-form pattern with:
- Email input field with validation
- CAPTCHA widget integration
- Submit button with loading states
- Error message display
- react-hook-form + zod validation
- useRequestMagicLink hook

Also added supporting code to make component compile:
- RequestMagicLinkRequest/Response types in @/types/auth
- requestMagicLink API function in auth-api.ts
- useRequestMagicLink hook
- createMagicLinkSchema and MagicLinkFormData in types/index.ts

Build verified successfully.

* Create MagicLinkSent component for confirmation sc

* Add magic link API functions to auth-api.ts

- Added MagicLinkLoginRequest type extending DeviceInfo with token and rememberMe fields
- Added magicLinkLogin function to authApi for /system/auth/magic-link/login endpoint
- Follows pattern from password-reset-api.ts with async/await and extractData helper
- Returns AuthResponse for authentication flow completion

* Create React hooks for magic link flow

Created useMagicLinkLogin hook following the useLogin pattern. The hook:
- Uses useMutation from react-query for API calls
- Handles MFA requirements (verification and setup)
- Handles device approval flow for risk-based authentication
- Updates auth state and navigates on successful login
- Provides callback options for different auth flows

Also exported both useRequestMagicLink and useMagicLinkLogin from the
hooks index for easy consumption.

Build verified successfully.

* Create /magic-link-login route for token validation

* Add 'Sign in with magic link' option to login page

- Export MagicLinkForm and MagicLinkSent from auth components
- Add toggle between password and magic link login modes
- Implement state management for login mode switching
- Show MagicLinkSent component after successful magic link request
- Add translation keys for toggle buttons (useMagicLink, usePassword)
- Add missing magicLink translation keys (email, button, sending, sent, sentMessage)

* Add i18n translations for magic link feature

* End-to-end magic link flow verification

Verified magic link passwordless login functionality:

✅ API Endpoints:
- POST /api/system/auth/magic-link/request returns 200
- Token generation and storage working
- Anti-enumeration implemented
- Rate limiting applied
- Audit logging functional

✅ Database:
- magic_link_tokens table operational
- Token hashing (SHA256) verified
- 15-minute expiration configured
- Single-use enforcement via is_used column
- Previous tokens auto-invalidated

✅ Security Features:
- Cryptographically secure tokens (32 bytes)
- Collision prevention (3 retries)
- CAPTCHA integration (configurable)
- Rate limiting on sensitive endpoints

✅ Frontend:
- MagicLinkForm component built
- Login page integration complete
- /magic-link-login route created
- Translations (EN/DE) added
- React hooks implemented

✅ Email Templates:
- Templates created (en-US, de-DE)
- Subjects configured in subjects.json
- Variables properly defined

⚠️ Email Worker Note:
Email worker has environment configuration issue preventing
actual SMTP sending. This is a deployment concern, not a code
issue. Emails are correctly queued to RabbitMQ.

Services tested:
- Backend API (port 5096) ✅
- Frontend (port 5176) ✅
- PostgreSQL ✅
- RabbitMQ ✅
- MailHog ✅

Test results documented in:
- .specs/002-magic-link-passwordless-login/e2e-test-results.md
- backend/test-magic-link.md

All magic link feature code is complete and functional.

* Update API documentation with magic link endpoints

- Enabled XML documentation generation in ExoAuth.Api.csproj
- Configured Swagger to include XML comments from generated documentation file
- Magic link endpoints now documented in Swagger/OpenAPI with:
  * POST /api/system/auth/magic-link/request - Request magic link email
  * POST /api/system/auth/magic-link/login - Login with magic link token
- Both endpoints include proper summaries, request/response schemas, and status codes
- Added swagger-verification.md with verification steps

* Add unit tests for magic link feature

- Add MagicLinkToken entity tests (token creation, hashing, expiration, validation)
- Add RequestMagicLinkHandler tests (email handling, CAPTCHA, user states)
- Add LoginWithMagicLinkHandler tests (auth flow, MFA, device approval)
- Add validator tests for RequestMagicLink and LoginWithMagicLink commands
- Update TestDataFactory with MagicLinkToken helpers
- Update MockDbContext with MagicLinkTokens DbSet

* fix: check siteKey in captchaRequired to prevent disabled button

* fix: back to login button on magic link sent page

* chore: remove deprecated Email section from appsettings

Email configuration is now database-driven (Task 025/026).
The old static Email section in appsettings is no longer used.

* ci: add develop branch to CI workflow triggers

* fix: remove BOM from migration file

---------

Co-authored-by: jxljan <juljan.blischke@gmail.com>

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

* Revert "feat(frontend): move all system routes to /system/* prefix (#39)" (#40)

This reverts commit c0e2b9f.

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>
juljanblischke added a commit that referenced this pull request Jan 20, 2026
* feat(frontend): move all system routes to /system/* prefix (#39)

* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* fix: add captcha.error translation and protected DbContext constructor

- Add missing `auth:captcha.error` translation key in EN and DE auth.json
- Add protected constructor to AppDbContext for DbContext inheritance support
  (required by Pro's ProDbContext which extends AppDbContext)

* Add Magic Link Passwordless Login Feature (#38)

* Create MagicLinkToken entity with token generation

Created MagicLinkToken entity for passwordless authentication following
PasswordResetToken pattern:
- Token generation using cryptographically secure random bytes (32 bytes)
- SHA256 hashing for secure token storage
- 15-minute expiration window (configurable)
- Single-use validation with IsUsed/UsedAt tracking
- Token validation against stored hash
- Inherits from BaseEntity for standard Id/CreatedAt/UpdatedAt fields

Simplified compared to PasswordResetToken (removed code-based auth).

* Add MagicLinkToken EF Core configuration

* Add DbSet<MagicLinkToken> to IAppDbContext and AppDbContext

* Create and apply EF Core migration for MagicLinkToken

* Create IMagicLinkService interface

* Implement MagicLinkService with collision prevention

Implemented MagicLinkService following PasswordResetService pattern:
- CreateMagicLinkAsync with collision prevention (3 retries)
- ValidateTokenAsync for token validation
- MarkAsUsedAsync for single-use enforcement
- InvalidateAllTokensAsync for user token invalidation
- SHA256 token hashing for secure comparison
- 15-minute expiration (configurable via Auth:MagicLinkExpiryMinutes)
- Comprehensive logging via ILogger

Build verified: 0 errors, 0 warnings

* Register IMagicLinkService in DI container

* Create RequestMagicLink command, handler, and validator

Created RequestMagicLink CQRS command with handler and validator following ForgotPassword pattern:
- RequestMagicLinkCommand: Command with email, captchaToken, ipAddress parameters
- RequestMagicLinkHandler: Handler with captcha validation, user lookup, token creation, email sending, audit logging, anti-enumeration response
- RequestMagicLinkValidator: FluentValidation validator for email format
- Added MagicLinkRequested, MagicLinkLogin, MagicLinkLoginFailed audit actions to AuditActions
- Added SendMagicLinkAsync method to IEmailService and EmailService implementation
- Handler validates CAPTCHA, checks user exists/active/not-anonymized, creates magic link token, sends email, logs audit event
- Always returns success response to prevent email enumeration
- Build verified: 0 errors, 0 warnings

* Create LoginWithMagicLink command, handler, and validator

- Created LoginWithMagicLinkCommand with token and device info parameters
- Created LoginWithMagicLinkValidator for token validation
- Created LoginWithMagicLinkHandler with full authentication flow:
  * Validates magic link token via IMagicLinkService
  * Marks token as used after validation
  * Handles MFA if enabled (returns RequiresMfa response)
  * Handles MFA setup requirement for system permission users
  * Device tracking and risk scoring (new device approval flow)
  * Spoofing detection for trusted devices
  * Session creation with access and refresh tokens
  * Login pattern recording for risk analysis
  * Comprehensive audit logging
  * New location email notification
- Added MagicLinkTokenInvalidException to AuthException.cs
- Handler follows LoginHandler pattern for consistency
- Build verified successfully with 0 errors/warnings

* Create magic link email templates (English and German)

* Add email template subjects for magic link

Added magic-link subjects to both English and German subjects.json files:
- English: 'Your magic link to sign in'
- German: 'Ihr Magic Link zum Anmelden'

Note: Task spec indicated modifying EmailTemplateService.cs, but the correct
approach is to add subjects to subjects.json files, which EmailTemplateService
loads dynamically.

* Add POST /api/system/auth/magic-link/request endpoint

* Add POST /api/system/auth/magic-link/login endpoint

* Create MagicLinkForm component for requesting magic link

Created MagicLinkForm component following accept-invite-form pattern with:
- Email input field with validation
- CAPTCHA widget integration
- Submit button with loading states
- Error message display
- react-hook-form + zod validation
- useRequestMagicLink hook

Also added supporting code to make component compile:
- RequestMagicLinkRequest/Response types in @/types/auth
- requestMagicLink API function in auth-api.ts
- useRequestMagicLink hook
- createMagicLinkSchema and MagicLinkFormData in types/index.ts

Build verified successfully.

* Create MagicLinkSent component for confirmation sc

* Add magic link API functions to auth-api.ts

- Added MagicLinkLoginRequest type extending DeviceInfo with token and rememberMe fields
- Added magicLinkLogin function to authApi for /system/auth/magic-link/login endpoint
- Follows pattern from password-reset-api.ts with async/await and extractData helper
- Returns AuthResponse for authentication flow completion

* Create React hooks for magic link flow

Created useMagicLinkLogin hook following the useLogin pattern. The hook:
- Uses useMutation from react-query for API calls
- Handles MFA requirements (verification and setup)
- Handles device approval flow for risk-based authentication
- Updates auth state and navigates on successful login
- Provides callback options for different auth flows

Also exported both useRequestMagicLink and useMagicLinkLogin from the
hooks index for easy consumption.

Build verified successfully.

* Create /magic-link-login route for token validation

* Add 'Sign in with magic link' option to login page

- Export MagicLinkForm and MagicLinkSent from auth components
- Add toggle between password and magic link login modes
- Implement state management for login mode switching
- Show MagicLinkSent component after successful magic link request
- Add translation keys for toggle buttons (useMagicLink, usePassword)
- Add missing magicLink translation keys (email, button, sending, sent, sentMessage)

* Add i18n translations for magic link feature

* End-to-end magic link flow verification

Verified magic link passwordless login functionality:

✅ API Endpoints:
- POST /api/system/auth/magic-link/request returns 200
- Token generation and storage working
- Anti-enumeration implemented
- Rate limiting applied
- Audit logging functional

✅ Database:
- magic_link_tokens table operational
- Token hashing (SHA256) verified
- 15-minute expiration configured
- Single-use enforcement via is_used column
- Previous tokens auto-invalidated

✅ Security Features:
- Cryptographically secure tokens (32 bytes)
- Collision prevention (3 retries)
- CAPTCHA integration (configurable)
- Rate limiting on sensitive endpoints

✅ Frontend:
- MagicLinkForm component built
- Login page integration complete
- /magic-link-login route created
- Translations (EN/DE) added
- React hooks implemented

✅ Email Templates:
- Templates created (en-US, de-DE)
- Subjects configured in subjects.json
- Variables properly defined

⚠️ Email Worker Note:
Email worker has environment configuration issue preventing
actual SMTP sending. This is a deployment concern, not a code
issue. Emails are correctly queued to RabbitMQ.

Services tested:
- Backend API (port 5096) ✅
- Frontend (port 5176) ✅
- PostgreSQL ✅
- RabbitMQ ✅
- MailHog ✅

Test results documented in:
- .specs/002-magic-link-passwordless-login/e2e-test-results.md
- backend/test-magic-link.md

All magic link feature code is complete and functional.

* Update API documentation with magic link endpoints

- Enabled XML documentation generation in ExoAuth.Api.csproj
- Configured Swagger to include XML comments from generated documentation file
- Magic link endpoints now documented in Swagger/OpenAPI with:
  * POST /api/system/auth/magic-link/request - Request magic link email
  * POST /api/system/auth/magic-link/login - Login with magic link token
- Both endpoints include proper summaries, request/response schemas, and status codes
- Added swagger-verification.md with verification steps

* Add unit tests for magic link feature

- Add MagicLinkToken entity tests (token creation, hashing, expiration, validation)
- Add RequestMagicLinkHandler tests (email handling, CAPTCHA, user states)
- Add LoginWithMagicLinkHandler tests (auth flow, MFA, device approval)
- Add validator tests for RequestMagicLink and LoginWithMagicLink commands
- Update TestDataFactory with MagicLinkToken helpers
- Update MockDbContext with MagicLinkTokens DbSet

* fix: check siteKey in captchaRequired to prevent disabled button

* fix: back to login button on magic link sent page

* chore: remove deprecated Email section from appsettings

Email configuration is now database-driven (Task 025/026).
The old static Email section in appsettings is no longer used.

* ci: add develop branch to CI workflow triggers

* fix: remove BOM from migration file

---------

Co-authored-by: jxljan <juljan.blischke@gmail.com>

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

* Revert "feat(frontend): move all system routes to /system/* prefix (#39)" (#40)

This reverts commit c0e2b9f.

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>
juljanblischke added a commit that referenced this pull request Jan 20, 2026
* fix: add captcha.error translation and protected DbContext constructor

- Add missing `auth:captcha.error` translation key in EN and DE auth.json
- Add protected constructor to AppDbContext for DbContext inheritance support
  (required by Pro's ProDbContext which extends AppDbContext)

* Add Magic Link Passwordless Login Feature (#38)

* Create MagicLinkToken entity with token generation

Created MagicLinkToken entity for passwordless authentication following
PasswordResetToken pattern:
- Token generation using cryptographically secure random bytes (32 bytes)
- SHA256 hashing for secure token storage
- 15-minute expiration window (configurable)
- Single-use validation with IsUsed/UsedAt tracking
- Token validation against stored hash
- Inherits from BaseEntity for standard Id/CreatedAt/UpdatedAt fields

Simplified compared to PasswordResetToken (removed code-based auth).

* Add MagicLinkToken EF Core configuration

* Add DbSet<MagicLinkToken> to IAppDbContext and AppDbContext

* Create and apply EF Core migration for MagicLinkToken

* Create IMagicLinkService interface

* Implement MagicLinkService with collision prevention

Implemented MagicLinkService following PasswordResetService pattern:
- CreateMagicLinkAsync with collision prevention (3 retries)
- ValidateTokenAsync for token validation
- MarkAsUsedAsync for single-use enforcement
- InvalidateAllTokensAsync for user token invalidation
- SHA256 token hashing for secure comparison
- 15-minute expiration (configurable via Auth:MagicLinkExpiryMinutes)
- Comprehensive logging via ILogger

Build verified: 0 errors, 0 warnings

* Register IMagicLinkService in DI container

* Create RequestMagicLink command, handler, and validator

Created RequestMagicLink CQRS command with handler and validator following ForgotPassword pattern:
- RequestMagicLinkCommand: Command with email, captchaToken, ipAddress parameters
- RequestMagicLinkHandler: Handler with captcha validation, user lookup, token creation, email sending, audit logging, anti-enumeration response
- RequestMagicLinkValidator: FluentValidation validator for email format
- Added MagicLinkRequested, MagicLinkLogin, MagicLinkLoginFailed audit actions to AuditActions
- Added SendMagicLinkAsync method to IEmailService and EmailService implementation
- Handler validates CAPTCHA, checks user exists/active/not-anonymized, creates magic link token, sends email, logs audit event
- Always returns success response to prevent email enumeration
- Build verified: 0 errors, 0 warnings

* Create LoginWithMagicLink command, handler, and validator

- Created LoginWithMagicLinkCommand with token and device info parameters
- Created LoginWithMagicLinkValidator for token validation
- Created LoginWithMagicLinkHandler with full authentication flow:
  * Validates magic link token via IMagicLinkService
  * Marks token as used after validation
  * Handles MFA if enabled (returns RequiresMfa response)
  * Handles MFA setup requirement for system permission users
  * Device tracking and risk scoring (new device approval flow)
  * Spoofing detection for trusted devices
  * Session creation with access and refresh tokens
  * Login pattern recording for risk analysis
  * Comprehensive audit logging
  * New location email notification
- Added MagicLinkTokenInvalidException to AuthException.cs
- Handler follows LoginHandler pattern for consistency
- Build verified successfully with 0 errors/warnings

* Create magic link email templates (English and German)

* Add email template subjects for magic link

Added magic-link subjects to both English and German subjects.json files:
- English: 'Your magic link to sign in'
- German: 'Ihr Magic Link zum Anmelden'

Note: Task spec indicated modifying EmailTemplateService.cs, but the correct
approach is to add subjects to subjects.json files, which EmailTemplateService
loads dynamically.

* Add POST /api/system/auth/magic-link/request endpoint

* Add POST /api/system/auth/magic-link/login endpoint

* Create MagicLinkForm component for requesting magic link

Created MagicLinkForm component following accept-invite-form pattern with:
- Email input field with validation
- CAPTCHA widget integration
- Submit button with loading states
- Error message display
- react-hook-form + zod validation
- useRequestMagicLink hook

Also added supporting code to make component compile:
- RequestMagicLinkRequest/Response types in @/types/auth
- requestMagicLink API function in auth-api.ts
- useRequestMagicLink hook
- createMagicLinkSchema and MagicLinkFormData in types/index.ts

Build verified successfully.

* Create MagicLinkSent component for confirmation sc

* Add magic link API functions to auth-api.ts

- Added MagicLinkLoginRequest type extending DeviceInfo with token and rememberMe fields
- Added magicLinkLogin function to authApi for /system/auth/magic-link/login endpoint
- Follows pattern from password-reset-api.ts with async/await and extractData helper
- Returns AuthResponse for authentication flow completion

* Create React hooks for magic link flow

Created useMagicLinkLogin hook following the useLogin pattern. The hook:
- Uses useMutation from react-query for API calls
- Handles MFA requirements (verification and setup)
- Handles device approval flow for risk-based authentication
- Updates auth state and navigates on successful login
- Provides callback options for different auth flows

Also exported both useRequestMagicLink and useMagicLinkLogin from the
hooks index for easy consumption.

Build verified successfully.

* Create /magic-link-login route for token validation

* Add 'Sign in with magic link' option to login page

- Export MagicLinkForm and MagicLinkSent from auth components
- Add toggle between password and magic link login modes
- Implement state management for login mode switching
- Show MagicLinkSent component after successful magic link request
- Add translation keys for toggle buttons (useMagicLink, usePassword)
- Add missing magicLink translation keys (email, button, sending, sent, sentMessage)

* Add i18n translations for magic link feature

* End-to-end magic link flow verification

Verified magic link passwordless login functionality:

✅ API Endpoints:
- POST /api/system/auth/magic-link/request returns 200
- Token generation and storage working
- Anti-enumeration implemented
- Rate limiting applied
- Audit logging functional

✅ Database:
- magic_link_tokens table operational
- Token hashing (SHA256) verified
- 15-minute expiration configured
- Single-use enforcement via is_used column
- Previous tokens auto-invalidated

✅ Security Features:
- Cryptographically secure tokens (32 bytes)
- Collision prevention (3 retries)
- CAPTCHA integration (configurable)
- Rate limiting on sensitive endpoints

✅ Frontend:
- MagicLinkForm component built
- Login page integration complete
- /magic-link-login route created
- Translations (EN/DE) added
- React hooks implemented

✅ Email Templates:
- Templates created (en-US, de-DE)
- Subjects configured in subjects.json
- Variables properly defined

⚠️ Email Worker Note:
Email worker has environment configuration issue preventing
actual SMTP sending. This is a deployment concern, not a code
issue. Emails are correctly queued to RabbitMQ.

Services tested:
- Backend API (port 5096) ✅
- Frontend (port 5176) ✅
- PostgreSQL ✅
- RabbitMQ ✅
- MailHog ✅

Test results documented in:
- .specs/002-magic-link-passwordless-login/e2e-test-results.md
- backend/test-magic-link.md

All magic link feature code is complete and functional.

* Update API documentation with magic link endpoints

- Enabled XML documentation generation in ExoAuth.Api.csproj
- Configured Swagger to include XML comments from generated documentation file
- Magic link endpoints now documented in Swagger/OpenAPI with:
  * POST /api/system/auth/magic-link/request - Request magic link email
  * POST /api/system/auth/magic-link/login - Login with magic link token
- Both endpoints include proper summaries, request/response schemas, and status codes
- Added swagger-verification.md with verification steps

* Add unit tests for magic link feature

- Add MagicLinkToken entity tests (token creation, hashing, expiration, validation)
- Add RequestMagicLinkHandler tests (email handling, CAPTCHA, user states)
- Add LoginWithMagicLinkHandler tests (auth flow, MFA, device approval)
- Add validator tests for RequestMagicLink and LoginWithMagicLink commands
- Update TestDataFactory with MagicLinkToken helpers
- Update MockDbContext with MagicLinkTokens DbSet

* fix: check siteKey in captchaRequired to prevent disabled button

* fix: back to login button on magic link sent page

* chore: remove deprecated Email section from appsettings

Email configuration is now database-driven (Task 025/026).
The old static Email section in appsettings is no longer used.

* ci: add develop branch to CI workflow triggers

* fix: remove BOM from migration file

---------

Co-authored-by: jxljan <juljan.blischke@gmail.com>

* feat(frontend): move all system routes to /system/* prefix (#41)

* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

* feat(frontend): move all system routes to /system/* prefix (#39)

* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* fix: add captcha.error translation and protected DbContext constructor

- Add missing `auth:captcha.error` translation key in EN and DE auth.json
- Add protected constructor to AppDbContext for DbContext inheritance support
  (required by Pro's ProDbContext which extends AppDbContext)

* Add Magic Link Passwordless Login Feature (#38)

* Create MagicLinkToken entity with token generation

Created MagicLinkToken entity for passwordless authentication following
PasswordResetToken pattern:
- Token generation using cryptographically secure random bytes (32 bytes)
- SHA256 hashing for secure token storage
- 15-minute expiration window (configurable)
- Single-use validation with IsUsed/UsedAt tracking
- Token validation against stored hash
- Inherits from BaseEntity for standard Id/CreatedAt/UpdatedAt fields

Simplified compared to PasswordResetToken (removed code-based auth).

* Add MagicLinkToken EF Core configuration

* Add DbSet<MagicLinkToken> to IAppDbContext and AppDbContext

* Create and apply EF Core migration for MagicLinkToken

* Create IMagicLinkService interface

* Implement MagicLinkService with collision prevention

Implemented MagicLinkService following PasswordResetService pattern:
- CreateMagicLinkAsync with collision prevention (3 retries)
- ValidateTokenAsync for token validation
- MarkAsUsedAsync for single-use enforcement
- InvalidateAllTokensAsync for user token invalidation
- SHA256 token hashing for secure comparison
- 15-minute expiration (configurable via Auth:MagicLinkExpiryMinutes)
- Comprehensive logging via ILogger

Build verified: 0 errors, 0 warnings

* Register IMagicLinkService in DI container

* Create RequestMagicLink command, handler, and validator

Created RequestMagicLink CQRS command with handler and validator following ForgotPassword pattern:
- RequestMagicLinkCommand: Command with email, captchaToken, ipAddress parameters
- RequestMagicLinkHandler: Handler with captcha validation, user lookup, token creation, email sending, audit logging, anti-enumeration response
- RequestMagicLinkValidator: FluentValidation validator for email format
- Added MagicLinkRequested, MagicLinkLogin, MagicLinkLoginFailed audit actions to AuditActions
- Added SendMagicLinkAsync method to IEmailService and EmailService implementation
- Handler validates CAPTCHA, checks user exists/active/not-anonymized, creates magic link token, sends email, logs audit event
- Always returns success response to prevent email enumeration
- Build verified: 0 errors, 0 warnings

* Create LoginWithMagicLink command, handler, and validator

- Created LoginWithMagicLinkCommand with token and device info parameters
- Created LoginWithMagicLinkValidator for token validation
- Created LoginWithMagicLinkHandler with full authentication flow:
  * Validates magic link token via IMagicLinkService
  * Marks token as used after validation
  * Handles MFA if enabled (returns RequiresMfa response)
  * Handles MFA setup requirement for system permission users
  * Device tracking and risk scoring (new device approval flow)
  * Spoofing detection for trusted devices
  * Session creation with access and refresh tokens
  * Login pattern recording for risk analysis
  * Comprehensive audit logging
  * New location email notification
- Added MagicLinkTokenInvalidException to AuthException.cs
- Handler follows LoginHandler pattern for consistency
- Build verified successfully with 0 errors/warnings

* Create magic link email templates (English and German)

* Add email template subjects for magic link

Added magic-link subjects to both English and German subjects.json files:
- English: 'Your magic link to sign in'
- German: 'Ihr Magic Link zum Anmelden'

Note: Task spec indicated modifying EmailTemplateService.cs, but the correct
approach is to add subjects to subjects.json files, which EmailTemplateService
loads dynamically.

* Add POST /api/system/auth/magic-link/request endpoint

* Add POST /api/system/auth/magic-link/login endpoint

* Create MagicLinkForm component for requesting magic link

Created MagicLinkForm component following accept-invite-form pattern with:
- Email input field with validation
- CAPTCHA widget integration
- Submit button with loading states
- Error message display
- react-hook-form + zod validation
- useRequestMagicLink hook

Also added supporting code to make component compile:
- RequestMagicLinkRequest/Response types in @/types/auth
- requestMagicLink API function in auth-api.ts
- useRequestMagicLink hook
- createMagicLinkSchema and MagicLinkFormData in types/index.ts

Build verified successfully.

* Create MagicLinkSent component for confirmation sc

* Add magic link API functions to auth-api.ts

- Added MagicLinkLoginRequest type extending DeviceInfo with token and rememberMe fields
- Added magicLinkLogin function to authApi for /system/auth/magic-link/login endpoint
- Follows pattern from password-reset-api.ts with async/await and extractData helper
- Returns AuthResponse for authentication flow completion

* Create React hooks for magic link flow

Created useMagicLinkLogin hook following the useLogin pattern. The hook:
- Uses useMutation from react-query for API calls
- Handles MFA requirements (verification and setup)
- Handles device approval flow for risk-based authentication
- Updates auth state and navigates on successful login
- Provides callback options for different auth flows

Also exported both useRequestMagicLink and useMagicLinkLogin from the
hooks index for easy consumption.

Build verified successfully.

* Create /magic-link-login route for token validation

* Add 'Sign in with magic link' option to login page

- Export MagicLinkForm and MagicLinkSent from auth components
- Add toggle between password and magic link login modes
- Implement state management for login mode switching
- Show MagicLinkSent component after successful magic link request
- Add translation keys for toggle buttons (useMagicLink, usePassword)
- Add missing magicLink translation keys (email, button, sending, sent, sentMessage)

* Add i18n translations for magic link feature

* End-to-end magic link flow verification

Verified magic link passwordless login functionality:

✅ API Endpoints:
- POST /api/system/auth/magic-link/request returns 200
- Token generation and storage working
- Anti-enumeration implemented
- Rate limiting applied
- Audit logging functional

✅ Database:
- magic_link_tokens table operational
- Token hashing (SHA256) verified
- 15-minute expiration configured
- Single-use enforcement via is_used column
- Previous tokens auto-invalidated

✅ Security Features:
- Cryptographically secure tokens (32 bytes)
- Collision prevention (3 retries)
- CAPTCHA integration (configurable)
- Rate limiting on sensitive endpoints

✅ Frontend:
- MagicLinkForm component built
- Login page integration complete
- /magic-link-login route created
- Translations (EN/DE) added
- React hooks implemented

✅ Email Templates:
- Templates created (en-US, de-DE)
- Subjects configured in subjects.json
- Variables properly defined

⚠️ Email Worker Note:
Email worker has environment configuration issue preventing
actual SMTP sending. This is a deployment concern, not a code
issue. Emails are correctly queued to RabbitMQ.

Services tested:
- Backend API (port 5096) ✅
- Frontend (port 5176) ✅
- PostgreSQL ✅
- RabbitMQ ✅
- MailHog ✅

Test results documented in:
- .specs/002-magic-link-passwordless-login/e2e-test-results.md
- backend/test-magic-link.md

All magic link feature code is complete and functional.

* Update API documentation with magic link endpoints

- Enabled XML documentation generation in ExoAuth.Api.csproj
- Configured Swagger to include XML comments from generated documentation file
- Magic link endpoints now documented in Swagger/OpenAPI with:
  * POST /api/system/auth/magic-link/request - Request magic link email
  * POST /api/system/auth/magic-link/login - Login with magic link token
- Both endpoints include proper summaries, request/response schemas, and status codes
- Added swagger-verification.md with verification steps

* Add unit tests for magic link feature

- Add MagicLinkToken entity tests (token creation, hashing, expiration, validation)
- Add RequestMagicLinkHandler tests (email handling, CAPTCHA, user states)
- Add LoginWithMagicLinkHandler tests (auth flow, MFA, device approval)
- Add validator tests for RequestMagicLink and LoginWithMagicLink commands
- Update TestDataFactory with MagicLinkToken helpers
- Update MockDbContext with MagicLinkTokens DbSet

* fix: check siteKey in captchaRequired to prevent disabled button

* fix: back to login button on magic link sent page

* chore: remove deprecated Email section from appsettings

Email configuration is now database-driven (Task 025/026).
The old static Email section in appsettings is no longer used.

* ci: add develop branch to CI workflow triggers

* fix: remove BOM from migration file

---------

Co-authored-by: jxljan <juljan.blischke@gmail.com>

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

* Revert "feat(frontend): move all system routes to /system/* prefix (#39)" (#40)

This reverts commit c0e2b9f.

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

* chore: sync develop with main (#42)

* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

* feat(frontend): move all system routes to /system/* prefix (#39)

* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* fix: add captcha.error translation and protected DbContext constructor

- Add missing `auth:captcha.error` translation key in EN and DE auth.json
- Add protected constructor to AppDbContext for DbContext inheritance support
  (required by Pro's ProDbContext which extends AppDbContext)

* Add Magic Link Passwordless Login Feature (#38)

* Create MagicLinkToken entity with token generation

Created MagicLinkToken entity for passwordless authentication following
PasswordResetToken pattern:
- Token generation using cryptographically secure random bytes (32 bytes)
- SHA256 hashing for secure token storage
- 15-minute expiration window (configurable)
- Single-use validation with IsUsed/UsedAt tracking
- Token validation against stored hash
- Inherits from BaseEntity for standard Id/CreatedAt/UpdatedAt fields

Simplified compared to PasswordResetToken (removed code-based auth).

* Add MagicLinkToken EF Core configuration

* Add DbSet<MagicLinkToken> to IAppDbContext and AppDbContext

* Create and apply EF Core migration for MagicLinkToken

* Create IMagicLinkService interface

* Implement MagicLinkService with collision prevention

Implemented MagicLinkService following PasswordResetService pattern:
- CreateMagicLinkAsync with collision prevention (3 retries)
- ValidateTokenAsync for token validation
- MarkAsUsedAsync for single-use enforcement
- InvalidateAllTokensAsync for user token invalidation
- SHA256 token hashing for secure comparison
- 15-minute expiration (configurable via Auth:MagicLinkExpiryMinutes)
- Comprehensive logging via ILogger

Build verified: 0 errors, 0 warnings

* Register IMagicLinkService in DI container

* Create RequestMagicLink command, handler, and validator

Created RequestMagicLink CQRS command with handler and validator following ForgotPassword pattern:
- RequestMagicLinkCommand: Command with email, captchaToken, ipAddress parameters
- RequestMagicLinkHandler: Handler with captcha validation, user lookup, token creation, email sending, audit logging, anti-enumeration response
- RequestMagicLinkValidator: FluentValidation validator for email format
- Added MagicLinkRequested, MagicLinkLogin, MagicLinkLoginFailed audit actions to AuditActions
- Added SendMagicLinkAsync method to IEmailService and EmailService implementation
- Handler validates CAPTCHA, checks user exists/active/not-anonymized, creates magic link token, sends email, logs audit event
- Always returns success response to prevent email enumeration
- Build verified: 0 errors, 0 warnings

* Create LoginWithMagicLink command, handler, and validator

- Created LoginWithMagicLinkCommand with token and device info parameters
- Created LoginWithMagicLinkValidator for token validation
- Created LoginWithMagicLinkHandler with full authentication flow:
  * Validates magic link token via IMagicLinkService
  * Marks token as used after validation
  * Handles MFA if enabled (returns RequiresMfa response)
  * Handles MFA setup requirement for system permission users
  * Device tracking and risk scoring (new device approval flow)
  * Spoofing detection for trusted devices
  * Session creation with access and refresh tokens
  * Login pattern recording for risk analysis
  * Comprehensive audit logging
  * New location email notification
- Added MagicLinkTokenInvalidException to AuthException.cs
- Handler follows LoginHandler pattern for consistency
- Build verified successfully with 0 errors/warnings

* Create magic link email templates (English and German)

* Add email template subjects for magic link

Added magic-link subjects to both English and German subjects.json files:
- English: 'Your magic link to sign in'
- German: 'Ihr Magic Link zum Anmelden'

Note: Task spec indicated modifying EmailTemplateService.cs, but the correct
approach is to add subjects to subjects.json files, which EmailTemplateService
loads dynamically.

* Add POST /api/system/auth/magic-link/request endpoint

* Add POST /api/system/auth/magic-link/login endpoint

* Create MagicLinkForm component for requesting magic link

Created MagicLinkForm component following accept-invite-form pattern with:
- Email input field with validation
- CAPTCHA widget integration
- Submit button with loading states
- Error message display
- react-hook-form + zod validation
- useRequestMagicLink hook

Also added supporting code to make component compile:
- RequestMagicLinkRequest/Response types in @/types/auth
- requestMagicLink API function in auth-api.ts
- useRequestMagicLink hook
- createMagicLinkSchema and MagicLinkFormData in types/index.ts

Build verified successfully.

* Create MagicLinkSent component for confirmation sc

* Add magic link API functions to auth-api.ts

- Added MagicLinkLoginRequest type extending DeviceInfo with token and rememberMe fields
- Added magicLinkLogin function to authApi for /system/auth/magic-link/login endpoint
- Follows pattern from password-reset-api.ts with async/await and extractData helper
- Returns AuthResponse for authentication flow completion

* Create React hooks for magic link flow

Created useMagicLinkLogin hook following the useLogin pattern. The hook:
- Uses useMutation from react-query for API calls
- Handles MFA requirements (verification and setup)
- Handles device approval flow for risk-based authentication
- Updates auth state and navigates on successful login
- Provides callback options for different auth flows

Also exported both useRequestMagicLink and useMagicLinkLogin from the
hooks index for easy consumption.

Build verified successfully.

* Create /magic-link-login route for token validation

* Add 'Sign in with magic link' option to login page

- Export MagicLinkForm and MagicLinkSent from auth components
- Add toggle between password and magic link login modes
- Implement state management for login mode switching
- Show MagicLinkSent component after successful magic link request
- Add translation keys for toggle buttons (useMagicLink, usePassword)
- Add missing magicLink translation keys (email, button, sending, sent, sentMessage)

* Add i18n translations for magic link feature

* End-to-end magic link flow verification

Verified magic link passwordless login functionality:

✅ API Endpoints:
- POST /api/system/auth/magic-link/request returns 200
- Token generation and storage working
- Anti-enumeration implemented
- Rate limiting applied
- Audit logging functional

✅ Database:
- magic_link_tokens table operational
- Token hashing (SHA256) verified
- 15-minute expiration configured
- Single-use enforcement via is_used column
- Previous tokens auto-invalidated

✅ Security Features:
- Cryptographically secure tokens (32 bytes)
- Collision prevention (3 retries)
- CAPTCHA integration (configurable)
- Rate limiting on sensitive endpoints

✅ Frontend:
- MagicLinkForm component built
- Login page integration complete
- /magic-link-login route created
- Translations (EN/DE) added
- React hooks implemented

✅ Email Templates:
- Templates created (en-US, de-DE)
- Subjects configured in subjects.json
- Variables properly defined

⚠️ Email Worker Note:
Email worker has environment configuration issue preventing
actual SMTP sending. This is a deployment concern, not a code
issue. Emails are correctly queued to RabbitMQ.

Services tested:
- Backend API (port 5096) ✅
- Frontend (port 5176) ✅
- PostgreSQL ✅
- RabbitMQ ✅
- MailHog ✅

Test results documented in:
- .specs/002-magic-link-passwordless-login/e2e-test-results.md
- backend/test-magic-link.md

All magic link feature code is complete and functional.

* Update API documentation with magic link endpoints

- Enabled XML documentation generation in ExoAuth.Api.csproj
- Configured Swagger to include XML comments from generated documentation file
- Magic link endpoints now documented in Swagger/OpenAPI with:
  * POST /api/system/auth/magic-link/request - Request magic link email
  * POST /api/system/auth/magic-link/login - Login with magic link token
- Both endpoints include proper summaries, request/response schemas, and status codes
- Added swagger-verification.md with verification steps

* Add unit tests for magic link feature

- Add MagicLinkToken entity tests (token creation, hashing, expiration, validation)
- Add RequestMagicLinkHandler tests (email handling, CAPTCHA, user states)
- Add LoginWithMagicLinkHandler tests (auth flow, MFA, device approval)
- Add validator tests for RequestMagicLink and LoginWithMagicLink commands
- Update TestDataFactory with MagicLinkToken helpers
- Update MockDbContext with MagicLinkTokens DbSet

* fix: check siteKey in captchaRequired to prevent disabled button

* fix: back to login button on magic link sent page

* chore: remove deprecated Email section from appsettings

Email configuration is now database-driven (Task 025/026).
The old static Email section in appsettings is no longer used.

* ci: add develop branch to CI workflow triggers

* fix: remove BOM from migration file

---------

Co-authored-by: jxljan <juljan.blischke@gmail.com>

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

* Revert "feat(frontend): move all system routes to /system/* prefix (#39)" (#40)

This reverts commit c0e2b9f.

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

* chore: merge main into develop (#43)

* feat(frontend): move all system routes to /system/* prefix (#39)

* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* fix: add captcha.error translation and protected DbContext constructor

- Add missing `auth:captcha.error` translation key in EN and DE auth.json
- Add protected constructor to AppDbContext for DbContext inheritance support
  (required by Pro's ProDbContext which extends AppDbContext)

* Add Magic Link Passwordless Login Feature (#38)

* Create MagicLinkToken entity with token generation

Created MagicLinkToken entity for passwordless authentication following
PasswordResetToken pattern:
- Token generation using cryptographically secure random bytes (32 bytes)
- SHA256 hashing for secure token storage
- 15-minute expiration window (configurable)
- Single-use validation with IsUsed/UsedAt tracking
- Token validation against stored hash
- Inherits from BaseEntity for standard Id/CreatedAt/UpdatedAt fields

Simplified compared to PasswordResetToken (removed code-based auth).

* Add MagicLinkToken EF Core configuration

* Add DbSet<MagicLinkToken> to IAppDbContext and AppDbContext

* Create and apply EF Core migration for MagicLinkToken

* Create IMagicLinkService interface

* Implement MagicLinkService with collision prevention

Implemented MagicLinkService following PasswordResetService pattern:
- CreateMagicLinkAsync with collision prevention (3 retries)
- ValidateTokenAsync for token validation
- MarkAsUsedAsync for single-use enforcement
- InvalidateAllTokensAsync for user token invalidation
- SHA256 token hashing for secure comparison
- 15-minute expiration (configurable via Auth:MagicLinkExpiryMinutes)
- Comprehensive logging via ILogger

Build verified: 0 errors, 0 warnings

* Register IMagicLinkService in DI container

* Create RequestMagicLink command, handler, and validator

Created RequestMagicLink CQRS command with handler and validator following ForgotPassword pattern:
- RequestMagicLinkCommand: Command with email, captchaToken, ipAddress parameters
- RequestMagicLinkHandler: Handler with captcha validation, user lookup, token creation, email sending, audit logging, anti-enumeration response
- RequestMagicLinkValidator: FluentValidation validator for email format
- Added MagicLinkRequested, MagicLinkLogin, MagicLinkLoginFailed audit actions to AuditActions
- Added SendMagicLinkAsync method to IEmailService and EmailService implementation
- Handler validates CAPTCHA, checks user exists/active/not-anonymized, creates magic link token, sends email, logs audit event
- Always returns success response to prevent email enumeration
- Build verified: 0 errors, 0 warnings

* Create LoginWithMagicLink command, handler, and validator

- Created LoginWithMagicLinkCommand with token and device info parameters
- Created LoginWithMagicLinkValidator for token validation
- Created LoginWithMagicLinkHandler with full authentication flow:
  * Validates magic link token via IMagicLinkService
  * Marks token as used after validation
  * Handles MFA if enabled (returns RequiresMfa response)
  * Handles MFA setup requirement for system permission users
  * Device tracking and risk scoring (new device approval flow)
  * Spoofing detection for trusted devices
  * Session creation with access and refresh tokens
  * Login pattern recording for risk analysis
  * Comprehensive audit logging
  * New location email notification
- Added MagicLinkTokenInvalidException to AuthException.cs
- Handler follows LoginHandler pattern for consistency
- Build verified successfully with 0 errors/warnings

* Create magic link email templates (English and German)

* Add email template subjects for magic link

Added magic-link subjects to both English and German subjects.json files:
- English: 'Your magic link to sign in'
- German: 'Ihr Magic Link zum Anmelden'

Note: Task spec indicated modifying EmailTemplateService.cs, but the correct
approach is to add subjects to subjects.json files, which EmailTemplateService
loads dynamically.

* Add POST /api/system/auth/magic-link/request endpoint

* Add POST /api/system/auth/magic-link/login endpoint

* Create MagicLinkForm component for requesting magic link

Created MagicLinkForm component following accept-invite-form pattern with:
- Email input field with validation
- CAPTCHA widget integration
- Submit button with loading states
- Error message display
- react-hook-form + zod validation
- useRequestMagicLink hook

Also added supporting code to make component compile:
- RequestMagicLinkRequest/Response types in @/types/auth
- requestMagicLink API function in auth-api.ts
- useRequestMagicLink hook
- createMagicLinkSchema and MagicLinkFormData in types/index.ts

Build verified successfully.

* Create MagicLinkSent component for confirmation sc

* Add magic link API functions to auth-api.ts

- Added MagicLinkLoginRequest type extending DeviceInfo with token and rememberMe fields
- Added magicLinkLogin function to authApi for /system/auth/magic-link/login endpoint
- Follows pattern from password-reset-api.ts with async/await and extractData helper
- Returns AuthResponse for authentication flow completion

* Create React hooks for magic link flow

Created useMagicLinkLogin hook following the useLogin pattern. The hook:
- Uses useMutation from react-query for API calls
- Handles MFA requirements (verification and setup)
- Handles device approval flow for risk-based authentication
- Updates auth state and navigates on successful login
- Provides callback options for different auth flows

Also exported both useRequestMagicLink and useMagicLinkLogin from the
hooks index for easy consumption.

Build verified successfully.

* Create /magic-link-login route for token validation

* Add 'Sign in with magic link' option to login page

- Export MagicLinkForm and MagicLinkSent from auth components
- Add toggle between password and magic link login modes
- Implement state management for login mode switching
- Show MagicLinkSent component after successful magic link request
- Add translation keys for toggle buttons (useMagicLink, usePassword)
- Add missing magicLink translation keys (email, button, sending, sent, sentMessage)

* Add i18n translations for magic link feature

* End-to-end magic link flow verification

Verified magic link passwordless login functionality:

✅ API Endpoints:
- POST /api/system/auth/magic-link/request returns 200
- Token generation and storage working
- Anti-enumeration implemented
- Rate limiting applied
- Audit logging functional

✅ Database:
- magic_link_tokens table operational
- Token hashing (SHA256) verified
- 15-minute expiration configured
- Single-use enforcement via is_used column
- Previous tokens auto-invalidated

✅ Security Features:
- Cryptographically secure tokens (32 bytes)
- Collision prevention (3 retries)
- CAPTCHA integration (configurable)
- Rate limiting on sensitive endpoints

✅ Frontend:
- MagicLinkForm component built
- Login page integration complete
- /magic-link-login route created
- Translations (EN/DE) added
- React hooks implemented

✅ Email Templates:
- Templates created (en-US, de-DE)
- Subjects configured in subjects.json
- Variables properly defined

⚠️ Email Worker Note:
Email worker has environment configuration issue preventing
actual SMTP sending. This is a deployment concern, not a code
issue. Emails are correctly queued to RabbitMQ.

Services tested:
- Backend API (port 5096) ✅
- Frontend (port 5176) ✅
- PostgreSQL ✅
- RabbitMQ ✅
- MailHog ✅

Test results documented in:
- .specs/002-magic-link-passwordless-login/e2e-test-results.md
- backend/test-magic-link.md

All magic link feature code is complete and functional.

* Update API documentation with magic link endpoints

- Enabled XML documentation generation in ExoAuth.Api.csproj
- Configured Swagger to include XML comments from generated documentation file
- Magic link endpoints now documented in Swagger/OpenAPI with:
  * POST /api/system/auth/magic-link/request - Request magic link email
  * POST /api/system/auth/magic-link/login - Login with magic link token
- Both endpoints include proper summaries, request/response schemas, and status codes
- Added swagger-verification.md with verification steps

* Add unit tests for magic link feature

- Add MagicLinkToken entity tests (token creation, hashing, expiration, validation)
- Add RequestMagicLinkHandler tests (email handling, CAPTCHA, user states)
- Add LoginWithMagicLinkHandler tests (auth flow, MFA, device approval)
- Add validator tests for RequestMagicLink and LoginWithMagicLink commands
- Update TestDataFactory with MagicLinkToken helpers
- Update MockDbContext with MagicLinkTokens DbSet

* fix: check siteKey in captchaRequired to prevent disabled button

* fix: back to login button on magic link sent page

* chore: remove deprecated Email section from appsettings

Email configuration is now database-driven (Task 025/026).
The old static Email section in appsettings is no longer used.

* ci: add develop branch to CI workflow triggers

* fix: remove BOM from migration file

---------

Co-authored-by: jxljan <juljan.blischke@gmail.com>

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

* Revert "feat(frontend): move all system routes to /system/* prefix (#39)" (#40)

This reverts commit c0e2b9f.

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>
juljanblischke added a commit that referenced this pull request Jan 20, 2026
* feat(frontend): move all system routes to /system/* prefix (#39)

* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* fix: add captcha.error translation and protected DbContext constructor

- Add missing `auth:captcha.error` translation key in EN and DE auth.json
- Add protected constructor to AppDbContext for DbContext inheritance support
  (required by Pro's ProDbContext which extends AppDbContext)

* Add Magic Link Passwordless Login Feature (#38)

* Create MagicLinkToken entity with token generation

Created MagicLinkToken entity for passwordless authentication following
PasswordResetToken pattern:
- Token generation using cryptographically secure random bytes (32 bytes)
- SHA256 hashing for secure token storage
- 15-minute expiration window (configurable)
- Single-use validation with IsUsed/UsedAt tracking
- Token validation against stored hash
- Inherits from BaseEntity for standard Id/CreatedAt/UpdatedAt fields

Simplified compared to PasswordResetToken (removed code-based auth).

* Add MagicLinkToken EF Core configuration

* Add DbSet<MagicLinkToken> to IAppDbContext and AppDbContext

* Create and apply EF Core migration for MagicLinkToken

* Create IMagicLinkService interface

* Implement MagicLinkService with collision prevention

Implemented MagicLinkService following PasswordResetService pattern:
- CreateMagicLinkAsync with collision prevention (3 retries)
- ValidateTokenAsync for token validation
- MarkAsUsedAsync for single-use enforcement
- InvalidateAllTokensAsync for user token invalidation
- SHA256 token hashing for secure comparison
- 15-minute expiration (configurable via Auth:MagicLinkExpiryMinutes)
- Comprehensive logging via ILogger

Build verified: 0 errors, 0 warnings

* Register IMagicLinkService in DI container

* Create RequestMagicLink command, handler, and validator

Created RequestMagicLink CQRS command with handler and validator following ForgotPassword pattern:
- RequestMagicLinkCommand: Command with email, captchaToken, ipAddress parameters
- RequestMagicLinkHandler: Handler with captcha validation, user lookup, token creation, email sending, audit logging, anti-enumeration response
- RequestMagicLinkValidator: FluentValidation validator for email format
- Added MagicLinkRequested, MagicLinkLogin, MagicLinkLoginFailed audit actions to AuditActions
- Added SendMagicLinkAsync method to IEmailService and EmailService implementation
- Handler validates CAPTCHA, checks user exists/active/not-anonymized, creates magic link token, sends email, logs audit event
- Always returns success response to prevent email enumeration
- Build verified: 0 errors, 0 warnings

* Create LoginWithMagicLink command, handler, and validator

- Created LoginWithMagicLinkCommand with token and device info parameters
- Created LoginWithMagicLinkValidator for token validation
- Created LoginWithMagicLinkHandler with full authentication flow:
  * Validates magic link token via IMagicLinkService
  * Marks token as used after validation
  * Handles MFA if enabled (returns RequiresMfa response)
  * Handles MFA setup requirement for system permission users
  * Device tracking and risk scoring (new device approval flow)
  * Spoofing detection for trusted devices
  * Session creation with access and refresh tokens
  * Login pattern recording for risk analysis
  * Comprehensive audit logging
  * New location email notification
- Added MagicLinkTokenInvalidException to AuthException.cs
- Handler follows LoginHandler pattern for consistency
- Build verified successfully with 0 errors/warnings

* Create magic link email templates (English and German)

* Add email template subjects for magic link

Added magic-link subjects to both English and German subjects.json files:
- English: 'Your magic link to sign in'
- German: 'Ihr Magic Link zum Anmelden'

Note: Task spec indicated modifying EmailTemplateService.cs, but the correct
approach is to add subjects to subjects.json files, which EmailTemplateService
loads dynamically.

* Add POST /api/system/auth/magic-link/request endpoint

* Add POST /api/system/auth/magic-link/login endpoint

* Create MagicLinkForm component for requesting magic link

Created MagicLinkForm component following accept-invite-form pattern with:
- Email input field with validation
- CAPTCHA widget integration
- Submit button with loading states
- Error message display
- react-hook-form + zod validation
- useRequestMagicLink hook

Also added supporting code to make component compile:
- RequestMagicLinkRequest/Response types in @/types/auth
- requestMagicLink API function in auth-api.ts
- useRequestMagicLink hook
- createMagicLinkSchema and MagicLinkFormData in types/index.ts

Build verified successfully.

* Create MagicLinkSent component for confirmation sc

* Add magic link API functions to auth-api.ts

- Added MagicLinkLoginRequest type extending DeviceInfo with token and rememberMe fields
- Added magicLinkLogin function to authApi for /system/auth/magic-link/login endpoint
- Follows pattern from password-reset-api.ts with async/await and extractData helper
- Returns AuthResponse for authentication flow completion

* Create React hooks for magic link flow

Created useMagicLinkLogin hook following the useLogin pattern. The hook:
- Uses useMutation from react-query for API calls
- Handles MFA requirements (verification and setup)
- Handles device approval flow for risk-based authentication
- Updates auth state and navigates on successful login
- Provides callback options for different auth flows

Also exported both useRequestMagicLink and useMagicLinkLogin from the
hooks index for easy consumption.

Build verified successfully.

* Create /magic-link-login route for token validation

* Add 'Sign in with magic link' option to login page

- Export MagicLinkForm and MagicLinkSent from auth components
- Add toggle between password and magic link login modes
- Implement state management for login mode switching
- Show MagicLinkSent component after successful magic link request
- Add translation keys for toggle buttons (useMagicLink, usePassword)
- Add missing magicLink translation keys (email, button, sending, sent, sentMessage)

* Add i18n translations for magic link feature

* End-to-end magic link flow verification

Verified magic link passwordless login functionality:

✅ API Endpoints:
- POST /api/system/auth/magic-link/request returns 200
- Token generation and storage working
- Anti-enumeration implemented
- Rate limiting applied
- Audit logging functional

✅ Database:
- magic_link_tokens table operational
- Token hashing (SHA256) verified
- 15-minute expiration configured
- Single-use enforcement via is_used column
- Previous tokens auto-invalidated

✅ Security Features:
- Cryptographically secure tokens (32 bytes)
- Collision prevention (3 retries)
- CAPTCHA integration (configurable)
- Rate limiting on sensitive endpoints

✅ Frontend:
- MagicLinkForm component built
- Login page integration complete
- /magic-link-login route created
- Translations (EN/DE) added
- React hooks implemented

✅ Email Templates:
- Templates created (en-US, de-DE)
- Subjects configured in subjects.json
- Variables properly defined

⚠️ Email Worker Note:
Email worker has environment configuration issue preventing
actual SMTP sending. This is a deployment concern, not a code
issue. Emails are correctly queued to RabbitMQ.

Services tested:
- Backend API (port 5096) ✅
- Frontend (port 5176) ✅
- PostgreSQL ✅
- RabbitMQ ✅
- MailHog ✅

Test results documented in:
- .specs/002-magic-link-passwordless-login/e2e-test-results.md
- backend/test-magic-link.md

All magic link feature code is complete and functional.

* Update API documentation with magic link endpoints

- Enabled XML documentation generation in ExoAuth.Api.csproj
- Configured Swagger to include XML comments from generated documentation file
- Magic link endpoints now documented in Swagger/OpenAPI with:
  * POST /api/system/auth/magic-link/request - Request magic link email
  * POST /api/system/auth/magic-link/login - Login with magic link token
- Both endpoints include proper summaries, request/response schemas, and status codes
- Added swagger-verification.md with verification steps

* Add unit tests for magic link feature

- Add MagicLinkToken entity tests (token creation, hashing, expiration, validation)
- Add RequestMagicLinkHandler tests (email handling, CAPTCHA, user states)
- Add LoginWithMagicLinkHandler tests (auth flow, MFA, device approval)
- Add validator tests for RequestMagicLink and LoginWithMagicLink commands
- Update TestDataFactory with MagicLinkToken helpers
- Update MockDbContext with MagicLinkTokens DbSet

* fix: check siteKey in captchaRequired to prevent disabled button

* fix: back to login button on magic link sent page

* chore: remove deprecated Email section from appsettings

Email configuration is now database-driven (Task 025/026).
The old static Email section in appsettings is no longer used.

* ci: add develop branch to CI workflow triggers

* fix: remove BOM from migration file

---------

Co-authored-by: jxljan <juljan.blischke@gmail.com>

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

* Revert "feat(frontend): move all system routes to /system/* prefix (#39)" (#40)

This reverts commit c0e2b9f.

* release: merge develop into main (#44)

* fix: add captcha.error translation and protected DbContext constructor

- Add missing `auth:captcha.error` translation key in EN and DE auth.json
- Add protected constructor to AppDbContext for DbContext inheritance support
  (required by Pro's ProDbContext which extends AppDbContext)

* Add Magic Link Passwordless Login Feature (#38)

* Create MagicLinkToken entity with token generation

Created MagicLinkToken entity for passwordless authentication following
PasswordResetToken pattern:
- Token generation using cryptographically secure random bytes (32 bytes)
- SHA256 hashing for secure token storage
- 15-minute expiration window (configurable)
- Single-use validation with IsUsed/UsedAt tracking
- Token validation against stored hash
- Inherits from BaseEntity for standard Id/CreatedAt/UpdatedAt fields

Simplified compared to PasswordResetToken (removed code-based auth).

* Add MagicLinkToken EF Core configuration

* Add DbSet<MagicLinkToken> to IAppDbContext and AppDbContext

* Create and apply EF Core migration for MagicLinkToken

* Create IMagicLinkService interface

* Implement MagicLinkService with collision prevention

Implemented MagicLinkService following PasswordResetService pattern:
- CreateMagicLinkAsync with collision prevention (3 retries)
- ValidateTokenAsync for token validation
- MarkAsUsedAsync for single-use enforcement
- InvalidateAllTokensAsync for user token invalidation
- SHA256 token hashing for secure comparison
- 15-minute expiration (configurable via Auth:MagicLinkExpiryMinutes)
- Comprehensive logging via ILogger

Build verified: 0 errors, 0 warnings

* Register IMagicLinkService in DI container

* Create RequestMagicLink command, handler, and validator

Created RequestMagicLink CQRS command with handler and validator following ForgotPassword pattern:
- RequestMagicLinkCommand: Command with email, captchaToken, ipAddress parameters
- RequestMagicLinkHandler: Handler with captcha validation, user lookup, token creation, email sending, audit logging, anti-enumeration response
- RequestMagicLinkValidator: FluentValidation validator for email format
- Added MagicLinkRequested, MagicLinkLogin, MagicLinkLoginFailed audit actions to AuditActions
- Added SendMagicLinkAsync method to IEmailService and EmailService implementation
- Handler validates CAPTCHA, checks user exists/active/not-anonymized, creates magic link token, sends email, logs audit event
- Always returns success response to prevent email enumeration
- Build verified: 0 errors, 0 warnings

* Create LoginWithMagicLink command, handler, and validator

- Created LoginWithMagicLinkCommand with token and device info parameters
- Created LoginWithMagicLinkValidator for token validation
- Created LoginWithMagicLinkHandler with full authentication flow:
  * Validates magic link token via IMagicLinkService
  * Marks token as used after validation
  * Handles MFA if enabled (returns RequiresMfa response)
  * Handles MFA setup requirement for system permission users
  * Device tracking and risk scoring (new device approval flow)
  * Spoofing detection for trusted devices
  * Session creation with access and refresh tokens
  * Login pattern recording for risk analysis
  * Comprehensive audit logging
  * New location email notification
- Added MagicLinkTokenInvalidException to AuthException.cs
- Handler follows LoginHandler pattern for consistency
- Build verified successfully with 0 errors/warnings

* Create magic link email templates (English and German)

* Add email template subjects for magic link

Added magic-link subjects to both English and German subjects.json files:
- English: 'Your magic link to sign in'
- German: 'Ihr Magic Link zum Anmelden'

Note: Task spec indicated modifying EmailTemplateService.cs, but the correct
approach is to add subjects to subjects.json files, which EmailTemplateService
loads dynamically.

* Add POST /api/system/auth/magic-link/request endpoint

* Add POST /api/system/auth/magic-link/login endpoint

* Create MagicLinkForm component for requesting magic link

Created MagicLinkForm component following accept-invite-form pattern with:
- Email input field with validation
- CAPTCHA widget integration
- Submit button with loading states
- Error message display
- react-hook-form + zod validation
- useRequestMagicLink hook

Also added supporting code to make component compile:
- RequestMagicLinkRequest/Response types in @/types/auth
- requestMagicLink API function in auth-api.ts
- useRequestMagicLink hook
- createMagicLinkSchema and MagicLinkFormData in types/index.ts

Build verified successfully.

* Create MagicLinkSent component for confirmation sc

* Add magic link API functions to auth-api.ts

- Added MagicLinkLoginRequest type extending DeviceInfo with token and rememberMe fields
- Added magicLinkLogin function to authApi for /system/auth/magic-link/login endpoint
- Follows pattern from password-reset-api.ts with async/await and extractData helper
- Returns AuthResponse for authentication flow completion

* Create React hooks for magic link flow

Created useMagicLinkLogin hook following the useLogin pattern. The hook:
- Uses useMutation from react-query for API calls
- Handles MFA requirements (verification and setup)
- Handles device approval flow for risk-based authentication
- Updates auth state and navigates on successful login
- Provides callback options for different auth flows

Also exported both useRequestMagicLink and useMagicLinkLogin from the
hooks index for easy consumption.

Build verified successfully.

* Create /magic-link-login route for token validation

* Add 'Sign in with magic link' option to login page

- Export MagicLinkForm and MagicLinkSent from auth components
- Add toggle between password and magic link login modes
- Implement state management for login mode switching
- Show MagicLinkSent component after successful magic link request
- Add translation keys for toggle buttons (useMagicLink, usePassword)
- Add missing magicLink translation keys (email, button, sending, sent, sentMessage)

* Add i18n translations for magic link feature

* End-to-end magic link flow verification

Verified magic link passwordless login functionality:

✅ API Endpoints:
- POST /api/system/auth/magic-link/request returns 200
- Token generation and storage working
- Anti-enumeration implemented
- Rate limiting applied
- Audit logging functional

✅ Database:
- magic_link_tokens table operational
- Token hashing (SHA256) verified
- 15-minute expiration configured
- Single-use enforcement via is_used column
- Previous tokens auto-invalidated

✅ Security Features:
- Cryptographically secure tokens (32 bytes)
- Collision prevention (3 retries)
- CAPTCHA integration (configurable)
- Rate limiting on sensitive endpoints

✅ Frontend:
- MagicLinkForm component built
- Login page integration complete
- /magic-link-login route created
- Translations (EN/DE) added
- React hooks implemented

✅ Email Templates:
- Templates created (en-US, de-DE)
- Subjects configured in subjects.json
- Variables properly defined

⚠️ Email Worker Note:
Email worker has environment configuration issue preventing
actual SMTP sending. This is a deployment concern, not a code
issue. Emails are correctly queued to RabbitMQ.

Services tested:
- Backend API (port 5096) ✅
- Frontend (port 5176) ✅
- PostgreSQL ✅
- RabbitMQ ✅
- MailHog ✅

Test results documented in:
- .specs/002-magic-link-passwordless-login/e2e-test-results.md
- backend/test-magic-link.md

All magic link feature code is complete and functional.

* Update API documentation with magic link endpoints

- Enabled XML documentation generation in ExoAuth.Api.csproj
- Configured Swagger to include XML comments from generated documentation file
- Magic link endpoints now documented in Swagger/OpenAPI with:
  * POST /api/system/auth/magic-link/request - Request magic link email
  * POST /api/system/auth/magic-link/login - Login with magic link token
- Both endpoints include proper summaries, request/response schemas, and status codes
- Added swagger-verification.md with verification steps

* Add unit tests for magic link feature

- Add MagicLinkToken entity tests (token creation, hashing, expiration, validation)
- Add RequestMagicLinkHandler tests (email handling, CAPTCHA, user states)
- Add LoginWithMagicLinkHandler tests (auth flow, MFA, device approval)
- Add validator tests for RequestMagicLink and LoginWithMagicLink commands
- Update TestDataFactory with MagicLinkToken helpers
- Update MockDbContext with MagicLinkTokens DbSet

* fix: check siteKey in captchaRequired to prevent disabled button

* fix: back to login button on magic link sent page

* chore: remove deprecated Email section from appsettings

Email configuration is now database-driven (Task 025/026).
The old static Email section in appsettings is no longer used.

* ci: add develop branch to CI workflow triggers

* fix: remove BOM from migration file

---------

Co-authored-by: jxljan <juljan.blischke@gmail.com>

* feat(frontend): move all system routes to /system/* prefix (#41)

* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

* feat(frontend): move all system routes to /system/* prefix (#39)

* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* fix: add captcha.error translation and protected DbContext constructor

- Add missing `auth:captcha.error` translation key in EN and DE auth.json
- Add protected constructor to AppDbContext for DbContext inheritance support
  (required by Pro's ProDbContext which extends AppDbContext)

* Add Magic Link Passwordless Login Feature (#38)

* Create MagicLinkToken entity with token generation

Created MagicLinkToken entity for passwordless authentication following
PasswordResetToken pattern:
- Token generation using cryptographically secure random bytes (32 bytes)
- SHA256 hashing for secure token storage
- 15-minute expiration window (configurable)
- Single-use validation with IsUsed/UsedAt tracking
- Token validation against stored hash
- Inherits from BaseEntity for standard Id/CreatedAt/UpdatedAt fields

Simplified compared to PasswordResetToken (removed code-based auth).

* Add MagicLinkToken EF Core configuration

* Add DbSet<MagicLinkToken> to IAppDbContext and AppDbContext

* Create and apply EF Core migration for MagicLinkToken

* Create IMagicLinkService interface

* Implement MagicLinkService with collision prevention

Implemented MagicLinkService following PasswordResetService pattern:
- CreateMagicLinkAsync with collision prevention (3 retries)
- ValidateTokenAsync for token validation
- MarkAsUsedAsync for single-use enforcement
- InvalidateAllTokensAsync for user token invalidation
- SHA256 token hashing for secure comparison
- 15-minute expiration (configurable via Auth:MagicLinkExpiryMinutes)
- Comprehensive logging via ILogger

Build verified: 0 errors, 0 warnings

* Register IMagicLinkService in DI container

* Create RequestMagicLink command, handler, and validator

Created RequestMagicLink CQRS command with handler and validator following ForgotPassword pattern:
- RequestMagicLinkCommand: Command with email, captchaToken, ipAddress parameters
- RequestMagicLinkHandler: Handler with captcha validation, user lookup, token creation, email sending, audit logging, anti-enumeration response
- RequestMagicLinkValidator: FluentValidation validator for email format
- Added MagicLinkRequested, MagicLinkLogin, MagicLinkLoginFailed audit actions to AuditActions
- Added SendMagicLinkAsync method to IEmailService and EmailService implementation
- Handler validates CAPTCHA, checks user exists/active/not-anonymized, creates magic link token, sends email, logs audit event
- Always returns success response to prevent email enumeration
- Build verified: 0 errors, 0 warnings

* Create LoginWithMagicLink command, handler, and validator

- Created LoginWithMagicLinkCommand with token and device info parameters
- Created LoginWithMagicLinkValidator for token validation
- Created LoginWithMagicLinkHandler with full authentication flow:
  * Validates magic link token via IMagicLinkService
  * Marks token as used after validation
  * Handles MFA if enabled (returns RequiresMfa response)
  * Handles MFA setup requirement for system permission users
  * Device tracking and risk scoring (new device approval flow)
  * Spoofing detection for trusted devices
  * Session creation with access and refresh tokens
  * Login pattern recording for risk analysis
  * Comprehensive audit logging
  * New location email notification
- Added MagicLinkTokenInvalidException to AuthException.cs
- Handler follows LoginHandler pattern for consistency
- Build verified successfully with 0 errors/warnings

* Create magic link email templates (English and German)

* Add email template subjects for magic link

Added magic-link subjects to both English and German subjects.json files:
- English: 'Your magic link to sign in'
- German: 'Ihr Magic Link zum Anmelden'

Note: Task spec indicated modifying EmailTemplateService.cs, but the correct
approach is to add subjects to subjects.json files, which EmailTemplateService
loads dynamically.

* Add POST /api/system/auth/magic-link/request endpoint

* Add POST /api/system/auth/magic-link/login endpoint

* Create MagicLinkForm component for requesting magic link

Created MagicLinkForm component following accept-invite-form pattern with:
- Email input field with validation
- CAPTCHA widget integration
- Submit button with loading states
- Error message display
- react-hook-form + zod validation
- useRequestMagicLink hook

Also added supporting code to make component compile:
- RequestMagicLinkRequest/Response types in @/types/auth
- requestMagicLink API function in auth-api.ts
- useRequestMagicLink hook
- createMagicLinkSchema and MagicLinkFormData in types/index.ts

Build verified successfully.

* Create MagicLinkSent component for confirmation sc

* Add magic link API functions to auth-api.ts

- Added MagicLinkLoginRequest type extending DeviceInfo with token and rememberMe fields
- Added magicLinkLogin function to authApi for /system/auth/magic-link/login endpoint
- Follows pattern from password-reset-api.ts with async/await and extractData helper
- Returns AuthResponse for authentication flow completion

* Create React hooks for magic link flow

Created useMagicLinkLogin hook following the useLogin pattern. The hook:
- Uses useMutation from react-query for API calls
- Handles MFA requirements (verification and setup)
- Handles device approval flow for risk-based authentication
- Updates auth state and navigates on successful login
- Provides callback options for different auth flows

Also exported both useRequestMagicLink and useMagicLinkLogin from the
hooks index for easy consumption.

Build verified successfully.

* Create /magic-link-login route for token validation

* Add 'Sign in with magic link' option to login page

- Export MagicLinkForm and MagicLinkSent from auth components
- Add toggle between password and magic link login modes
- Implement state management for login mode switching
- Show MagicLinkSent component after successful magic link request
- Add translation keys for toggle buttons (useMagicLink, usePassword)
- Add missing magicLink translation keys (email, button, sending, sent, sentMessage)

* Add i18n translations for magic link feature

* End-to-end magic link flow verification

Verified magic link passwordless login functionality:

✅ API Endpoints:
- POST /api/system/auth/magic-link/request returns 200
- Token generation and storage working
- Anti-enumeration implemented
- Rate limiting applied
- Audit logging functional

✅ Database:
- magic_link_tokens table operational
- Token hashing (SHA256) verified
- 15-minute expiration configured
- Single-use enforcement via is_used column
- Previous tokens auto-invalidated

✅ Security Features:
- Cryptographically secure tokens (32 bytes)
- Collision prevention (3 retries)
- CAPTCHA integration (configurable)
- Rate limiting on sensitive endpoints

✅ Frontend:
- MagicLinkForm component built
- Login page integration complete
- /magic-link-login route created
- Translations (EN/DE) added
- React hooks implemented

✅ Email Templates:
- Templates created (en-US, de-DE)
- Subjects configured in subjects.json
- Variables properly defined

⚠️ Email Worker Note:
Email worker has environment configuration issue preventing
actual SMTP sending. This is a deployment concern, not a code
issue. Emails are correctly queued to RabbitMQ.

Services tested:
- Backend API (port 5096) ✅
- Frontend (port 5176) ✅
- PostgreSQL ✅
- RabbitMQ ✅
- MailHog ✅

Test results documented in:
- .specs/002-magic-link-passwordless-login/e2e-test-results.md
- backend/test-magic-link.md

All magic link feature code is complete and functional.

* Update API documentation with magic link endpoints

- Enabled XML documentation generation in ExoAuth.Api.csproj
- Configured Swagger to include XML comments from generated documentation file
- Magic link endpoints now documented in Swagger/OpenAPI with:
  * POST /api/system/auth/magic-link/request - Request magic link email
  * POST /api/system/auth/magic-link/login - Login with magic link token
- Both endpoints include proper summaries, request/response schemas, and status codes
- Added swagger-verification.md with verification steps

* Add unit tests for magic link feature

- Add MagicLinkToken entity tests (token creation, hashing, expiration, validation)
- Add RequestMagicLinkHandler tests (email handling, CAPTCHA, user states)
- Add LoginWithMagicLinkHandler tests (auth flow, MFA, device approval)
- Add validator tests for RequestMagicLink and LoginWithMagicLink commands
- Update TestDataFactory with MagicLinkToken helpers
- Update MockDbContext with MagicLinkTokens DbSet

* fix: check siteKey in captchaRequired to prevent disabled button

* fix: back to login button on magic link sent page

* chore: remove deprecated Email section from appsettings

Email configuration is now database-driven (Task 025/026).
The old static Email section in appsettings is no longer used.

* ci: add develop branch to CI workflow triggers

* fix: remove BOM from migration file

---------

Co-authored-by: jxljan <juljan.blischke@gmail.com>

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

* Revert "feat(frontend): move all system routes to /system/* prefix (#39)" (#40)

This reverts commit c0e2b9f.

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

* chore: sync develop with main (#42)

* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

* feat(frontend): move all system routes to /system/* prefix (#39)

* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* fix: add captcha.error translation and protected DbContext constructor

- Add missing `auth:captcha.error` translation key in EN and DE auth.json
- Add protected constructor to AppDbContext for DbContext inheritance support
  (required by Pro's ProDbContext which extends AppDbContext)

* Add Magic Link Passwordless Login Feature (#38)

* Create MagicLinkToken entity with token generation

Created MagicLinkToken entity for passwordless authentication following
PasswordResetToken pattern:
- Token generation using cryptographically secure random bytes (32 bytes)
- SHA256 hashing for secure token storage
- 15-minute expiration window (configurable)
- Single-use validation with IsUsed/UsedAt tracking
- Token validation against stored hash
- Inherits from BaseEntity for standard Id/CreatedAt/UpdatedAt fields

Simplified compared to PasswordResetToken (removed code-based auth).

* Add MagicLinkToken EF Core configuration

* Add DbSet<MagicLinkToken> to IAppDbContext and AppDbContext

* Create and apply EF Core migration for MagicLinkToken

* Create IMagicLinkService interface

* Implement MagicLinkService with collision prevention

Implemented MagicLinkService following PasswordResetService pattern:
- CreateMagicLinkAsync with collision prevention (3 retries)
- ValidateTokenAsync for token validation
- MarkAsUsedAsync for single-use enforcement
- InvalidateAllTokensAsync for user token invalidation
- SHA256 token hashing for secure comparison
- 15-minute expiration (configurable via Auth:MagicLinkExpiryMinutes)
- Comprehensive logging via ILogger

Build verified: 0 errors, 0 warnings

* Register IMagicLinkService in DI container

* Create RequestMagicLink command, handler, and validator

Created RequestMagicLink CQRS command with handler and validator following ForgotPassword pattern:
- RequestMagicLinkCommand: Command with email, captchaToken, ipAddress parameters
- RequestMagicLinkHandler: Handler with captcha validation, user lookup, token creation, email sending, audit logging, anti-enumeration response
- RequestMagicLinkValidator: FluentValidation validator for email format
- Added MagicLinkRequested, MagicLinkLogin, MagicLinkLoginFailed audit actions to AuditActions
- Added SendMagicLinkAsync method to IEmailService and EmailService implementation
- Handler validates CAPTCHA, checks user exists/active/not-anonymized, creates magic link token, sends email, logs audit event
- Always returns success response to prevent email enumeration
- Build verified: 0 errors, 0 warnings

* Create LoginWithMagicLink command, handler, and validator

- Created LoginWithMagicLinkCommand with token and device info parameters
- Created LoginWithMagicLinkValidator for token validation
- Created LoginWithMagicLinkHandler with full authentication flow:
  * Validates magic link token via IMagicLinkService
  * Marks token as used after validation
  * Handles MFA if enabled (returns RequiresMfa response)
  * Handles MFA setup requirement for system permission users
  * Device tracking and risk scoring (new device approval flow)
  * Spoofing detection for trusted devices
  * Session creation with access and refresh tokens
  * Login pattern recording for risk analysis
  * Comprehensive audit logging
  * New location email notification
- Added MagicLinkTokenInvalidException to AuthException.cs
- Handler follows LoginHandler pattern for consistency
- Build verified successfully with 0 errors/warnings

* Create magic link email templates (English and German)

* Add email template subjects for magic link

Added magic-link subjects to both English and German subjects.json files:
- English: 'Your magic link to sign in'
- German: 'Ihr Magic Link zum Anmelden'

Note: Task spec indicated modifying EmailTemplateService.cs, but the correct
approach is to add subjects to subjects.json files, which EmailTemplateService
loads dynamically.

* Add POST /api/system/auth/magic-link/request endpoint

* Add POST /api/system/auth/magic-link/login endpoint

* Create MagicLinkForm component for requesting magic link

Created MagicLinkForm component following accept-invite-form pattern with:
- Email input field with validation
- CAPTCHA widget integration
- Submit button with loading states
- Error message display
- react-hook-form + zod validation
- useRequestMagicLink hook

Also added supporting code to make component compile:
- RequestMagicLinkRequest/Response types in @/types/auth
- requestMagicLink API function in auth-api.ts
- useRequestMagicLink hook
- createMagicLinkSchema and MagicLinkFormData in types/index.ts

Build verified successfully.

* Create MagicLinkSent component for confirmation sc

* Add magic link API functions to auth-api.ts

- Added MagicLinkLoginRequest type extending DeviceInfo with token and rememberMe fields
- Added magicLinkLogin function to authApi for /system/auth/magic-link/login endpoint
- Follows pattern from password-reset-api.ts with async/await and extractData helper
- Returns AuthResponse for authentication flow completion

* Create React hooks for magic link flow

Created useMagicLinkLogin hook following the useLogin pattern. The hook:
- Uses useMutation from react-query for API calls
- Handles MFA requirements (verification and setup)
- Handles device approval flow for risk-based authentication
- Updates auth state and navigates on successful login
- Provides callback options for different auth flows

Also exported both useRequestMagicLink and useMagicLinkLogin from the
hooks index for easy consumption.

Build verified successfully.

* Create /magic-link-login route for token validation

* Add 'Sign in with magic link' option to login page

- Export MagicLinkForm and MagicLinkSent from auth components
- Add toggle between password and magic link login modes
- Implement state management for login mode switching
- Show MagicLinkSent component after successful magic link request
- Add translation keys for toggle buttons (useMagicLink, usePassword)
- Add missing magicLink translation keys (email, button, sending, sent, sentMessage)

* Add i18n translations for magic link feature

* End-to-end magic link flow verification

Verified magic link passwordless login functionality:

✅ API Endpoints:
- POST /api/system/auth/magic-link/request returns 200
- Token generation and storage working
- Anti-enumeration implemented
- Rate limiting applied
- Audit logging functional

✅ Database:
- magic_link_tokens table operational
- Token hashing (SHA256) verified
- 15-minute expiration configured
- Single-use enforcement via is_used column
- Previous tokens auto-invalidated

✅ Security Features:
- Cryptographically secure tokens (32 bytes)
- Collision prevention (3 retries)
- CAPTCHA integration (configurable)
- Rate limiting on sensitive endpoints

✅ Frontend:
- MagicLinkForm component built
- Login page integration complete
- /magic-link-login route created
- Translations (EN/DE) added
- React hooks implemented

✅ Email Templates:
- Templates created (en-US, de-DE)
- Subjects configured in subjects.json
- Variables properly defined

⚠️ Email Worker Note:
Email worker has environment configuration issue preventing
actual SMTP sending. This is a deployment concern, not a code
issue. Emails are correctly queued to RabbitMQ.

Services tested:
- Backend API (port 5096) ✅
- Frontend (port 5176) ✅
- PostgreSQL ✅
- RabbitMQ ✅
- MailHog ✅

Test results documented in:
- .specs/002-magic-link-passwordless-login/e2e-test-results.md
- backend/test-magic-link.md

All magic link feature code is complete and functional.

* Update API documentation with magic link endpoints

- Enabled XML documentation generation in ExoAuth.Api.csproj
- Configured Swagger to include XML comments from generated documentation file
- Magic link endpoints now documented in Swagger/OpenAPI with:
  * POST /api/system/auth/magic-link/request - Request magic link email
  * POST /api/system/auth/magic-link/login - Login with magic link token
- Both endpoints include proper summaries, request/response schemas, and status codes
- Added swagger-verification.md with verification steps

* Add unit tests for magic link feature

- Add MagicLinkToken entity tests (token creation, hashing, expiration, validation)
- Add RequestMagicLinkHandler tests (email handling, CAPTCHA, user states)
- Add LoginWithMagicLinkHandler tests (auth flow, MFA, device approval)
- Add validator tests for RequestMagicLink and LoginWithMagicLink commands
- Update TestDataFactory with MagicLinkToken helpers
- Update MockDbContext with MagicLinkTokens DbSet

* fix: check siteKey in captchaRequired to prevent disabled button

* fix: back to login button on magic link sent page

* chore: remove deprecated Email section from appsettings

Email configuration is now database-driven (Task 025/026).
The old static Email section in appsettings is no longer used.

* ci: add develop branch to CI workflow triggers

* fix: remove BOM from migration file

---------

Co-authored-by: jxljan <juljan.blischke@gmail.com>

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

* Revert "feat(frontend): move all system routes to /system/* prefix (#39)" (#40)

This reverts commit c0e2b9f.

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

* chore: merge main into develop (#43)

* feat(frontend): move all system routes to /system/* prefix (#39)

* Add missing captcha.error translation key

Added generic error message for captcha verification failures in both
EN and DE locales.

* fix: add captcha.error translation and protected DbContext constructor

- Add missing `auth:captcha.error` translation key in EN and DE auth.json
- Add protected constructor to AppDbContext for DbContext inheritance support
  (required by Pro's ProDbContext which extends AppDbContext)

* Add Magic Link Passwordless Login Feature (#38)

* Create MagicLinkToken entity with token generation

Created MagicLinkToken entity for passwordless authentication following
PasswordResetToken pattern:
- Token generation using cryptographically secure random bytes (32 bytes)
- SHA256 hashing for secure token storage
- 15-minute expiration window (configurable)
- Single-use validation with IsUsed/UsedAt tracking
- Token validation against stored hash
- Inherits from BaseEntity for standard Id/CreatedAt/UpdatedAt fields

Simplified compared to PasswordResetToken (removed code-based auth).

* Add MagicLinkToken EF Core configuration

* Add DbSet<MagicLinkToken> to IAppDbContext and AppDbContext

* Create and apply EF Core migration for MagicLinkToken

* Create IMagicLinkService interface

* Implement MagicLinkService with collision prevention

Implemented MagicLinkService following PasswordResetService pattern:
- CreateMagicLinkAsync with collision prevention (3 retries)
- ValidateTokenAsync for token validation
- MarkAsUsedAsync for single-use enforcement
- InvalidateAllTokensAsync for user token invalidation
- SHA256 token hashing for secure comparison
- 15-minute expiration (configurable via Auth:MagicLinkExpiryMinutes)
- Comprehensive logging via ILogger

Build verified: 0 errors, 0 warnings

* Register IMagicLinkService in DI container

* Create RequestMagicLink command, handler, and validator

Created RequestMagicLink CQRS command with handler and validator following ForgotPassword pattern:
- RequestMagicLinkCommand: Command with email, captchaToken, ipAddress parameters
- RequestMagicLinkHandler: Handler with captcha validation, user lookup, token creation, email sending, audit logging, anti-enumeration response
- RequestMagicLinkValidator: FluentValidation validator for email format
- Added MagicLinkRequested, MagicLinkLogin, MagicLinkLoginFailed audit actions to AuditActions
- Added SendMagicLinkAsync method to IEmailService and EmailService implementation
- Handler validates CAPTCHA, checks user exists/active/not-anonymized, creates magic link token, sends email, logs audit event
- Always returns success response to prevent email enumeration
- Build verified: 0 errors, 0 warnings

* Create LoginWithMagicLink command, handler, and validator

- Created LoginWithMagicLinkCommand with token and device info parameters
- Created LoginWithMagicLinkValidator for token validation
- Created LoginWithMagicLinkHandler with full authentication flow:
  * Validates magic link token via IMagicLinkService
  * Marks token as used after validation
  * Handles MFA if enabled (returns RequiresMfa response)
  * Handles MFA setup requirement for system permission users
  * Device tracking and risk scoring (new device approval flow)
  * Spoofing detection for trusted devices
  * Session creation with access and refresh tokens
  * Login pattern recording for risk analysis
  * Comprehensive audit logging
  * New location email notification
- Added MagicLinkTokenInvalidException to AuthException.cs
- Handler follows LoginHandler pattern for consistency
- Build verified successfully with 0 errors/warnings

* Create magic link email templates (English and German)

* Add email template subjects for magic link

Added magic-link subjects to both English and German subjects.json files:
- English: 'Your magic link to sign in'
- German: 'Ihr Magic Link zum Anmelden'

Note: Task spec indicated modifying EmailTemplateService.cs, but the correct
approach is to add subjects to subjects.json files, which EmailTemplateService
loads dynamically.

* Add POST /api/system/auth/magic-link/request endpoint

* Add POST /api/system/auth/magic-link/login endpoint

* Create MagicLinkForm component for requesting magic link

Created MagicLinkForm component following accept-invite-form pattern with:
- Email input field with validation
- CAPTCHA widget integration
- Submit button with loading states
- Error message display
- react-hook-form + zod validation
- useRequestMagicLink hook

Also added supporting code to make component compile:
- RequestMagicLinkRequest/Response types in @/types/auth
- requestMagicLink API function in auth-api.ts
- useRequestMagicLink hook
- createMagicLinkSchema and MagicLinkFormData in types/index.ts

Build verified successfully.

* Create MagicLinkSent component for confirmation sc

* Add magic link API functions to auth-api.ts

- Added MagicLinkLoginRequest type extending DeviceInfo with token and rememberMe fields
- Added magicLinkLogin function to authApi for /system/auth/magic-link/login endpoint
- Follows pattern from password-reset-api.ts with async/await and extractData helper
- Returns AuthResponse for authentication flow completion

* Create React hooks for magic link flow

Created useMagicLinkLogin hook following the useLogin pattern. The hook:
- Uses useMutation from react-query for API calls
- Handles MFA requirements (verification and setup)
- Handles device approval flow for risk-based authentication
- Updates auth state and navigates on successful login
- Provides callback options for different auth flows

Also exported both useRequestMagicLink and useMagicLinkLogin from the
hooks index for easy consumption.

Build verified successfully.

* Create /magic-link-login route for token validation

* Add 'Sign in with magic link' option to login page

- Export MagicLinkForm and MagicLinkSent from auth components
- Add toggle between password and magic link login modes
- Implement state management for login mode switching
- Show MagicLinkSent component after successful magic link request
- Add translation keys for toggle buttons (useMagicLink, usePassword)
- Add missing magicLink translation keys (email, button, sending, sent, sentMessage)

* Add i18n translations for magic link feature

* End-to-end magic link flow verification

Verified magic link passwordless login functionality:

✅ API Endpoints:
- POST /api/system/auth/magic-link/request returns 200
- Token generation and storage working
- Anti-enumeration implemented
- Rate limiting applied
- Audit logging functional

✅ Database:
- magic_link_tokens table operational
- Token hashing (SHA256) verified
- 15-minute expiration configured
- Single-use enforcement via is_used column
- Previous tokens auto-invalidated

✅ Security Features:
- Cryptographically secure tokens (32 bytes)
- Collision prevention (3 retries)
- CAPTCHA integration (configurable)
- Rate limiting on sensitive endpoints

✅ Frontend:
- MagicLinkForm component built
- Login page integration complete
- /magic-link-login route created
- Translations (EN/DE) added
- React hooks implemented

✅ Email Templates:
- Templates created (en-US, de-DE)
- Subjects configured in subjects.json
- Variables properly defined

⚠️ Email Worker Note:
Email worker has environment configuration issue preventing
actual SMTP sending. This is a deployment concern, not a code
issue. Emails are correctly queued to RabbitMQ.

Services tested:
- Backend API (port 5096) ✅
- Frontend (port 5176) ✅
- PostgreSQL ✅
- RabbitMQ ✅
- MailHog ✅

Test results documented in:
- .specs/002-magic-link-passwordless-login/e2e-test-results.md
- backend/test-magic-link.md

All magic link feature code is complete and functional.

* Update API documentation with magic link endpoints

- Enabled XML documentation generation in ExoAuth.Api.csproj
- Configured Swagger to include XML comments from generated documentation file
- Magic link endpoints now documented in Swagger/OpenAPI with:
  * POST /api/system/auth/magic-link/request - Request magic link email
  * POST /api/system/auth/magic-link/login - Login with magic link token
- Both endpoints include proper summaries, request/response schemas, and status codes
- Added swagger-verification.md with verification steps

* Add unit tests for magic link feature

- Add MagicLinkToken entity tests (token creation, hashing, expiration, validation)
- Add RequestMagicLinkHandler tests (email handling, CAPTCHA, user states)
- Add LoginWithMagicLinkHandler tests (auth flow, MFA, device approval)
- Add validator tests for RequestMagicLink and LoginWithMagicLink commands
- Update TestDataFactory with MagicLinkToken helpers
- Update MockDbContext with MagicLinkTokens DbSet

* fix: check siteKey in captchaRequired to prevent disabled button

* fix: back to login button on magic link sent page

* chore: remove deprecated Email section from appsettings

Email configuration is now database-driven (Task 025/026).
The old static Email section in appsettings is no longer used.

* ci: add develop branch to CI workflow triggers

* fix: remove BOM from migration file

---------

Co-authored-by: jxljan <juljan.blischke@gmail.com>

* feat(frontend): move all system routes to /system/* prefix

- Update __root.tsx with /system/* prefixed routes
- Update navigation.ts hrefs to /system/*
- Update index-page.tsx redirect to /system/login or /system/dashboard
- Rename Dashboard to System Dashboard in i18n (en/de)
- Update auth-context.tsx redirect paths
- Fix all hardcoded paths in components and hooks
- Update breadcrumbs to filter out /system prefix

Part of Task 028: Frontend Pro Setup - Routing Architecture

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

* Revert "feat(frontend): move all system routes to /system/* prefix (#39)" (#40)

This reverts commit c0e2b9f.

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>

---------

Co-authored-by: FlorianBlischkeHahnSoftware <127846411+FlorianBlischkeHahnSoftware@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants