Adminix Documentation Help

Security

Adminix is an admin panel package. Treat every request to Adminix routes as privileged application traffic.

Authorization

By default Adminix requires an authenticated user that implements AdminixUserInterface. The middleware checks getAdminCriteria() from that interface.

use AlexKudrya\Adminix\AdminixUser; use AlexKudrya\Adminix\AdminixUserInterface; class User extends Authenticatable implements AdminixUserInterface { use AdminixUser; }

Do not enable no_auth_access in production. It is intended only for local demos and isolated development environments.

Logout is a state-changing action and is exposed only as a POST route with CSRF protection. Use the package sidebar form or submit a POST request to adminix_login_logout; do not link to logout with a GET URL. Successful login regenerates the Laravel session ID. Logout invalidates the session and regenerates the CSRF token.

Server-side resource configuration

Create and save routes use the server-side module configuration for:

  • dataSource;

  • primary key;

  • writable fields;

  • readonly fields;

  • fields hidden from the current visibility context;

  • static hidden field values;

  • signed param:* hidden field values rendered by package views.

Legacy Blade forms still render hidden metadata for compatibility with the current frontend, but controllers do not trust hidden adminix_data_source, _primary_key, or arbitrary writable field lists from the request. param:* hidden values are accepted only from signed form context generated during server-side rendering; unsigned or tampered request values are ignored and then handled by normal validation.

Save flows reject requests with no writable input and return a not-found error when an update affects no rows. Create flows reject requests with no writable input. Modal API requests with malformed params return controlled JSON errors. Requests with missing module metadata and non-scalar list filter values are ignored or rejected with controlled errors instead of producing uncaught server errors. Adminix endpoint resolution is server-side: page, module, list, field, action, datasource, primary key, relation context, and writable fields are resolved from package configuration or signed context before an endpoint writes or reads data. Web and API endpoints return controlled redirects or JSON errors for invalid module/context/validation states.

Password fields use only server-side ResourceField::password() configuration for create/update availability. Stored password values are never returned into resource or modal form data, optional blank password updates are ignored, and confirmed() validates against Laravel's field_confirmation key. Adminix persists the submitted value as-is; consuming apps must own hashing, strength rules, and credential lifecycle policies.

Upload fields use only server-side ResourceField::upload() configuration for disk, directory, validation rules, remove behavior, and old-file cleanup. The request may contain a file payload or a remove checkbox, but it cannot choose a disk, directory, stored filename, or writable upload column. On update, scalar values submitted under an upload field name are rejected; only real uploaded files or an allowed remove checkbox can change stored upload paths. Readonly upload fields are ignored like other readonly fields. If validation or database update fails, Adminix cleans up newly stored files; previous files are deleted only after a successful replace/remove update when deleteReplaced is enabled. Resource create/update/upload audit events are emitted only after successful package write flows and contain server-derived module metadata, writable fields, subject, and upload descriptors. Recorder implementations must still persist audit rows with application-side tenant/user ownership rules.

Media browser URLs are server-side module configuration. MediaBrowserModule::fromDisk() is appropriate for public filesystem disks; private media should use application routes, temporary signed URLs, or storage helpers that enforce authorization before streaming or redirecting. The browser cannot choose media disk, directory, item list, or URL strategy. Image transform callbacks return application-owned thumbnail/preview URLs only; they must not trust browser-provided variants, storage paths, tenant IDs, or private object keys. Media preview and copy URL actions are read-only browser helpers. Media replace/remove actions only render server-declared forms with CSRF and method spoofing; consuming application routes must authorize the admin, tenant, owner, file key, upload validation, storage write, and deletion policy.

Field visibility helpers such as hiddenOnCreate(), hiddenOnUpdate(), hiddenOnModal(), hiddenOnDetail(), and hiddenOnIndex() are server-side module configuration. For create/update/modal/list writes, hidden-by-context fields are excluded from writable field resolution and validation whitelists. They are not authorization rules; keep tenant, owner, and permission checks in server-side criteria, guards, policies, or handlers.

Resource and detail relation managers resolve the parent record from server-side module props before building child UI. The relation list receives a server-owned foreign-key criterion; browser filters can narrow that query but cannot select another parent record. Relation create/edit modals use signed relation context for the parent resource and inject the child foreign key server-side. Child edit fetch/save adds the parent foreign-key criterion, so a child record from another parent returns a controlled not-found response instead of being updated.

List sorting accepts only asc and desc from the request. List lenses accept only configured server-side lens names from lens-{moduleName}. Lens default filters are applied only when the matching request filter key is absent; browser-provided filter keys are never silently replaced by lens defaults. List row details are read-only and opt-in per module through ListModule::rowDetails(). Detail values are prepared from server-declared ListRowDetails fields against the already scoped list records; the browser cannot choose datasource, criteria, field list, or primary key for the detail panel. Password row-detail fields do not return stored values. List CSV export is opt-in per module, uses the server-side list datasource and fields, requires signed page-param context, and ignores browser-provided datasource or column lists. Hidden list fields are excluded from CSV unless the field is explicitly marked exportable. When a tenant context is active, Adminix embeds the provider-approved tenant key and criteria hash in signed module endpoint contexts. Endpoint verification recalculates the current tenant context server-side and rejects stale, missing, or mismatched tenant payloads. Adminix also injects active provider criteria into Adminix-owned list/resource scopes, including rendered lists, resource fetches, CSV exports, bulk actions, reorder, soft-delete, clone, modal fetches, and resource update lookups. Create flows derive server-owned default values only from simple equality tenant criteria, such as tenant_id = 9; complex criteria constrain queries but are not written into create payloads. This prevents the browser from substituting tenant context for package-owned scopes, but custom handlers, imports, media routes, external writes, guards, and policies must still enforce application tenancy. Import preview is opt-in through ImportModule and resolves the target module server-side before reading a CSV upload. The preview endpoint accepts only a file payload plus page/module identifiers, applies the configured size limit, parses rows server-side, runs configured preview row validation server-side, and stores preview data in the session. Queued imports additionally store a server-owned temporary CSV copy and render execute controls only when queued() and handler() are configured. Failed-row CSV downloads verify signed import context and export only rows/messages from the current server-side preview validation report. The execute endpoint verifies a signed import context, requires the existing preview session, dispatches a queued job, and the job reparses the CSV and revalidates every row from the current server-side module config before calling the handler. Import routes do not trust browser-submitted datasource, writable fields, mapping, validation rules, failed rows, temporary paths, or persistence behavior. Import progress triggers only start same-page polling; progress state must come from the configured server-side progress handler. Queued import result downloads and reports are server-side handler metadata; signed URLs, storage, retention, and authorization belong to the consuming app. Application import handlers own idempotent database writes, failed-row storage, and audit rules. List row reorder is opt-in per module through ListModule::reorderable() or treeReorderable(), requires a signed rendered-row context, and accepts only a permutation of the visible primary keys. Tree reorder also signs the rendered parent map; submitted adminix_reorder_parent_ids must cover the same visible ID set, pass cycle validation, and use the parent field/root sentinel configured server-side. Tree reorder controls are not rendered for incomplete tree scopes where a visible row points to a parent outside the current rendered row set. Adminix resolves datasource, base criteria, relation scope, primary key, reorder field, tree parent field, and persistence strategy from server-side module configuration. The built-in SQL/Eloquent writer uses a transaction and a temporary sentinel value outside the current datasource range before assigning the existing order values to the new order, so permanent order values do not grow after repeated reorders and immediate unique constraints are not hit during normal swaps. For MongoDB, external stores, custom rank algorithms, or storage-specific locking/versioning, use reorderUsing() and keep the storage write server-side. List soft-delete row actions are opt-in per module through restoreAction(), forceDeleteAction(), or softDeleteActions(). Adminix requires an Eloquent SoftDeletes datasource, verifies a signed page-param context, re-resolves relation context and current list scope, and acts only on records that are still trashed(). Do not trust browser-provided datasource, primary-key names, deleted state, tenant ids, or param:* values for restore or permanent deletion flows. List clone actions are opt-in per module through cloneAction(), bulkCloneAction(), or cloneActions(). Adminix verifies signed context, reapplies relation context and current list scope, and derives clone data from server-side rendered index fields plus equality criteria values. Do not let the browser choose clone fields, datasource, primary-key names, writable fields, hidden tenant ids, or param:* values. Saved table views are opt-in per module through ListModule::savedTableViews() and require a signed table view context. The browser may submit a proposed preset name and state snapshot, but Adminix derives owner type and owner ID from the authenticated request user, resolves page/module/provider from server configuration, and normalizes allowed search, filter, lens, sort, column visibility, column order, column width, and density keys before calling the provider. Do not make table view ownership, tenant context, provider names, datasource, fields, filters, lenses, or sortable fields browser-authoritative. List bulk actions are opt-in per module and resolve the action by name from server-side ListModule::bulkActions(). Bulk requests may submit only selected scalar IDs and an action name. Adminix verifies signed page-param context, verifies signed relation context for relation child lists, applies the same datasource, primary key, base criteria, active lens, filters, search, sorting, and relation parent scope as the rendered list, and ignores IDs outside that scope. Handlers receive a scoped selected-record query; they must not rebuild writes from browser-provided datasource, writable fields, parent IDs, or hidden metadata. Bulk action audit metadata uses the same scope-filtered selected IDs; do not replace it with raw browser-selected IDs in listeners or recorders. Action handlers should read only declared adminix_action_fields values from BulkActionRequest::field()/fields(). Queued bulk actions are authorized before dispatch and reapply the signed context, saved query filters/search/lens/sorting, and current server-side list scope when the queued job runs. Queued audit entries record bulk.queued on dispatch and bulk.executed after the queued handler finishes. Typed action responses such as redirects, modals, downloads, and new-tab targets must be derived from trusted server-side state, not browser-owned datasource, IDs, field names, or tenant context. Search input escapes SQL LIKE wildcards and is capped before query application. Invalid date and date-range filter values are kept in the rendered filter state but ignored by the database query instead of producing a server error. Row action confirmation text is JSON-encoded before it is placed in inline JavaScript. Class-string data sources must be Eloquent models; non-model classes are rejected with a controlled package error.

Run Adminix Doctor during setup and before release to catch common configuration and module safety issues early:

php artisan adminix:doctor --strict

Doctor reports risky no_auth_access, invalid admin user model configuration, duplicate page identifiers, malformed criteria, invalid data sources, unsafe editable/reorder list shape, field visibility conflicts, and unsupported row-action criteria before the affected admin route is used.

Criteria validation uses the same operator contract in runtime queries, resource update lookup scopes, and Doctor diagnostics. Supported query operators are =, ==, !=, <>, >, <, >=, <=, like, and not like; row action visibility criteria remain limited to == and != because they compare already-rendered row values.

Validation

Put validation rules on module fields or module-level validation(). Update flows ignore the current row for string unique rules and Rule::unique() objects using the server-derived primary key.

Public exposure checklist

  • keep no_auth_access set to false;

  • implement AdminixUserInterface on the configured user model;

  • configure strict getAdminCriteria() rules;

  • configure only intended fields as editable or writable;

  • keep sensitive model fields out of Adminix modules unless they are intentionally managed;

  • disallow indexing Adminix URLs in robots.txt.

Last modified: 01 July 2026