Authentication

Login methods, registration, roles, and session handling in Dracory applications.

Authentication

Dracory ships a complete session-based authentication system backed by the userstore and sessionstore packages. Auth controllers live in internal/controllers/auth/ and are mounted by internal/controllers/auth/routes.go.

Login Methods

Enabled login mechanisms are selected at runtime with the AUTH_LOGIN_METHODS environment variable — a comma-separated (or JSON array) list. The first entry is the primary method rendered at /auth/login; each additional method is mounted at its own /auth/<method>-login path and is offered as an alternative on the login page. The deprecated singular AUTH_LOGIN_METHOD is still honoured as a fallback.

Supported methods:

  • otp (default) – in-house email one-time-password login.
  • magiclink – in-house email magic-link login.
  • password – in-house email/password login.
  • authknight – delegates authentication to the external AuthKnight service.

Auth Routes

Path Mounted When
/auth/login Always — serves the primary login method
/auth/otp-login, /auth/magiclink-login, /auth/password-login, /auth/authknight-login When the method is enabled but is not primary
/auth/magiclink-callback When magiclink is enabled
/auth/authknight-callback When authknight is enabled
/auth/forgot-password, /auth/password-reset When password is among the enabled methods
/auth/register When AUTH_REGISTRATION_ENABLED=yes
/auth/logout Always

Registration & Email Allowlist

  • AUTH_REGISTRATION_ENABLED – set to no to disable the public registration page (default yes).
  • AUTH_EMAILS_ALLOWED_ACCESS – optional comma-separated allowlist of email domains/addresses. When empty, all emails are allowed. Enforcement is consolidated in internal/rules/auth (EmailAllowedRule).

When password auth is enabled, the register page is the public sign-up form (email + password) that logs the user in. Otherwise it is the post-authentication profile completion form.

CSRF Protection

AUTH_CSRF_SECRET signs CSRF tokens. It is required in production and staging — configuration loading fails if missing. In other environments a random secret is generated and a warning is logged. See the Environment guide for details.

Rate Limiting

Sensitive auth endpoints are rate-limited to 5 requests per minute per IP (RateLimitByIPMiddleware(5, 60)) to blunt brute-force attempts. Registration routes allow 10 requests per minute. Logout is deliberately unthrottled.

User Roles

Roles are stored in the userstore role and user_role tables (enabled via RolesEnabled in internal/config/store_builders.go). A migration creates the tables, seeds four default roles — administrator, manager, superuser, user — and backfills assignments from the legacy role column.

Helper functions in internal/helpers/user_roles.go:

  • UserActiveRoleHandles(ctx, app, userID) – map of the user's active role handles.
  • UserHasActiveRole(ctx, app, user, handle) – single-role check.
  • UserHasAnyActiveRole(ctx, app, user, handles...) – any-of check.
  • UserActiveRoleAssign(ctx, app, userID, handle) – assign a role to a user.

New users created via shared.SessionLogin are automatically assigned the user role.

Sessions

Successful logins flow through internal/controllers/auth/shared.SessionLogin, which creates the session record and sets the auth cookie. Cookie Secure flags are environment-aware: relaxed in development, enforced under TLS in production. Session expiry is maintained by a background goroutine started with the server.