name: admin-gui description: Documentation of the HTMX admin GUI including template rendering, session management, CRUD patterns, and the GUIHandler structure. license: MIT
Overview
The admin GUI is an HTMX-powered web interface at /gui/*. It provides a complete management dashboard for the Auth API platform. The main handler is internal/admin/gui_handler.go (4976 lines, the largest file in the project).
Architecture
GUIHandler (internal/admin/gui_handler.go)
|-- AccountService -> admin auth, sessions, 2FA, CSRF
|-- DashboardService -> stats aggregation
|-- Repository -> data access (tenants, apps, users, etc.)
|-- SettingsService -> system settings management
|-- EmailService -> email template/server management
|-- RBACService -> role/permission management
|-- PasskeyService -> WebAuthn for admin accounts
Template Rendering (web/renderer.go)
Embedded filesystem: //go:embed templates in web/renderer.go
Template structure:
web/templates/
layouts/ -> base layout files (*.tmpl)
partials/ -> reusable fragments (*.tmpl) -- also served as standalone for HTMX
pages/ -> full page templates (*.tmpl)
Parsing strategy:
- Full pages = layouts + partials + page file (rendered via
c.HTML()) - HTMX fragments = partials rendered standalone (for dynamic swaps)
Template data struct (web.TemplateData):
type TemplateData struct {
ActivePage string // Current page identifier for nav highlighting
AdminUsername string // From auth context
AdminID string // From auth context
CSRFToken string // From CSRF middleware
FlashSuccess string // Flash messages
FlashError string
Error string // Login-specific error
Username string // Pre-filled username on login error
Redirect string // Post-login redirect URL
TempToken string // 2FA temp token
TwoFAMethod string // "totp" or "email"
Data interface{} // Page-specific arbitrary data
}
Template functions available (web.defaultFuncMap):
formatDate,formatDateTime,formatDateTimeFull-- date formattingtimeAgo-- human-readable relative timeupper,lower,title-- string transformssafeHTML,safeURL-- mark content as safe (no escaping)eq-- string equalityderef-- dereference *time.Time (nil-safe)isExpired-- check if time is in the pastadd,sub-- arithmetic for pagination
Authentication Flow
Standard Login
GET /gui/login -> LoginPage (render login form)
POST /gui/login -> LoginSubmit [rate limited: 5/min]
-> accountService.Authenticate(username, password)
-> If 2FA: CreatePending2FASession -> redirect to /gui/2fa-verify
-> If no 2FA: CreateSession -> set cookie -> redirect to /gui/
2FA Verification
GET /gui/2fa-verify -> TwoFAVerifyPage (render 2FA form)
POST /gui/2fa-verify -> TwoFAVerifySubmit
-> Validate TOTP code, email code, or recovery code
-> PromotePendingSession -> set cookie -> redirect
Passkey Login (passwordless)
POST /gui/passkey-login/begin -> PasskeyLoginBegin (returns JSON challenge)
POST /gui/passkey-login/finish -> PasskeyLoginFinish (validates assertion)
-> CreateSession -> set cookie -> return JSON success
Magic Link Login (passwordless)
POST /gui/magic-link-login -> MagicLinkLoginRequest
-> Generate token in Redis (10 min) -> send email
GET /gui/magic-link-login/verify -> MagicLinkLoginVerify
-> Validate token -> CreateSession -> set cookie -> redirect
Session Cookie
- Name:
admin_session(constant:web.AdminSessionCookie) - Path:
/gui - Flags: HttpOnly, SameSite=Strict, Secure (auto-detected)
- Set via
web.SetSessionCookie(), cleared viaweb.ClearSessionCookie()
HTMX CRUD Pattern
Every entity domain follows a consistent pattern. Example for tenants:
GET /gui/tenants -> TenantPage (full page with layout)
GET /gui/tenants/list -> TenantList (HTMX partial, paginated table)
GET /gui/tenants/new -> TenantCreateForm (HTMX partial, form)
POST /gui/tenants -> TenantCreate (creates, returns alert + triggers list refresh)
GET /gui/tenants/form-cancel -> TenantFormCancel (empty response, cancels form)
GET /gui/tenants/:id/edit -> TenantEditForm (HTMX partial, pre-filled form)
PUT /gui/tenants/:id -> TenantUpdate (updates, returns alert + triggers list refresh)
GET /gui/tenants/:id/delete -> TenantDeleteConfirm (HTMX partial, confirmation modal)
DELETE /gui/tenants/:id -> TenantDelete (deletes, triggers list refresh)
HTMX signals: Methods set HX-Trigger headers to signal events:
- Entity events:
tenantDeleted,roleDeleted,sessionListRefresh,socialAccountUnlinked,permissionsSaved, etc. - These trigger list refreshes and modal closes on the client side
Error handling: Errors are returned as Bootstrap alert HTML snippets via c.String() or c.HTML().
GUIHandler Method Groups
| Approx Lines | Section | Entity/Feature |
|---|---|---|
| 1-120 | Auth | Login, Logout, 2FA verify |
| 120-200 | Dashboard | Stats display |
| 200-550 | Tenants | Full CRUD |
| 550-950 | Applications | Full CRUD |
| 950-1350 | OAuth Configs | Full CRUD + toggle enabled |
| 1350-1900 | Users | List (paginated, searchable), detail, toggle active |
| 1900-2200 | Activity Logs | List (paginated, filterable), detail |
| 2200-2600 | API Keys | CRUD + revoke |
| 2600-2850 | Settings | Three-tier resolution display, update, reset |
| 2850-3050 | Email (Servers/Templates/Types) | Full CRUD for each |
| 3050-3100 | My Account (Email/Password) | Profile management |
| 3100-3330 | My Account (2FA) | TOTP generate/verify, email 2FA, recovery codes |
| 3335-3480 | My Account (Passkeys) | Register, delete, rename |
| 3480-3715 | Roles | CRUD + permission assignment modal |
| 3715-3865 | Permissions | List, create |
| 3865-4115 | User Roles | Assign, revoke, search users, dynamic dropdowns |
| 4115-4210 | Social Account Mgmt | Unlink (with lockout prevention) |
| 4215-4290 | Passkey Mgmt (for users) | Delete user's passkey |
| 4290-4340 | Helpers | parseVariablesFromForm, escapeHTML |
| 4340-4420 | Passkey Login | WebAuthn discoverable login ceremony |
| 4420-4600 | Magic Link Login | Request, verify |
| 4600-4976 | Session Management | List (cross-app), detail, revoke, per-user sessions |
CSRF Protection
Middleware: internal/middleware/csrf.go
- GET requests: generate CSRF token, set in context as
csrf_token - POST/PUT/DELETE: read from
X-CSRF-Tokenheader (HTMX) or_csrfform field - Token validated against session via
sessionValidator.ValidateCSRFToken()
HTMX sends CSRF token via header: templates set hx-headers='{"X-CSRF-Token": "{{.CSRFToken}}"}'
Rate Limiting (GUI-specific)
| Endpoint | Limit | Window | Lockout |
|---|---|---|---|
| POST /gui/login | 5/min | 60s | 10 -> 15min |
| POST /gui/passkey-login/* | 10/min | 60s | 20 -> 15min |
| POST /gui/magic-link-login | 3/15min | 15min | none |
GUI rate limiting sets web.RateLimitErrorKey in context (doesn't abort), letting the handler render the error in the form.
Static Assets
Embedded via web/static/embed.go using //go:embed. Served at /gui/static/*.
Key Dependencies
admin.AccountServiceimplementsweb.SessionValidator(for GUI auth + CSRF middleware)admin.Repositoryimplementsweb.ApiKeyValidator(for admin/app API key middleware)- Both interfaces defined in
web/context_keys.goto avoid import cycles
When To Use This Skill
Load this skill when working on the admin web interface, HTMX templates, GUI authentication, or any /gui/* route.