Skip to content
Core Concepts

Authorization ​

Remove a field, a fieldset, or the whole form for users who shouldn't see it.

php
TextInput::make('salary')
    ->number()
    ->authorize(fn () => auth()->user()->can('manage-salaries'));

When to use: admin-only fields, role-based sections, or forms that only some users may submit.

Authorization is different from visibility. Visibility depends on what the user types and is checked in the browser. Authorization is decided on the server, and unauthorized items never reach the browser at all.

Examples ​

Each example is a live form built from the PHP below it. The checks use plain booleans so the result is fixed; in your app they would come from the current user, as the comments show.

Basic ​

salary fails its check, so it is missing from the preview and from the submitted data. notes passes because authorizedUnless() gets false.

php
use Erag\InertiaForms\Fields\Textarea;
use Erag\InertiaForms\Fields\TextInput;

[
    TextInput::make('name')->required(),
    TextInput::make('email')->email()->required(),
    // In your app: ->authorizedWhen($user->can('manage-salaries'))
    TextInput::make('salary')->number()->prefix('€')->authorizedWhen(false),
    // In your app: ->authorizedUnless($user->isGuest())
    Textarea::make('notes')->rows(2)->authorizedUnless(false),
];

A whole fieldset ​

One check on the fieldset removes every field inside it. Only the Profile section is rendered.

php
use Erag\InertiaForms\Fields\Combobox;
use Erag\InertiaForms\Fields\Fieldset;
use Erag\InertiaForms\Fields\TextInput;
use Erag\InertiaForms\Fields\Toggle;

[
    Fieldset::make('Profile')->columns(2)->fields([
        TextInput::make('name')->required(),
        TextInput::make('email')->email()->required(),
    ]),
    // In your app: ->authorize(fn () => auth()->user()->isAdmin())
    Fieldset::make('Admin')->authorize(false)->fields([
        Toggle::make('is_verified'),
        Combobox::make('plan')->options(['free' => 'Free', 'pro' => 'Pro']),
    ]),
];

Advanced: role-based sections ​

The role is passed to the constructor, and the checks read it. The preview is built for an HR user: Compensation is shown, but bonus_eligible is removed because it also needs the admin role. Every check on an item must pass.

php
use Erag\InertiaForms\Fields\Combobox;
use Erag\InertiaForms\Fields\Fieldset;
use Erag\InertiaForms\Fields\Submit;
use Erag\InertiaForms\Fields\Textarea;
use Erag\InertiaForms\Fields\TextInput;
use Erag\InertiaForms\Fields\Toggle;
use Erag\InertiaForms\Form;

class EmployeeForm extends Form
{
    protected ?string $actionUrl = '/employees';

    public function __construct(private string $role = 'viewer', private bool $isOwnRecord = false) {}

    public function fields(): array
    {
        return [
            Fieldset::make('Profile')->columns(2)->fields([
                TextInput::make('name')->required(),
                TextInput::make('job_title'),
            ]),
            Fieldset::make('Compensation')
                ->description('Only HR and admins get this section.')
                ->authorize(fn () => in_array($this->role, ['hr', 'admin'], true))
                ->columns(2)
                ->fields([
                    TextInput::make('salary')->number()->prefix('€')->required(),
                    Combobox::make('pay_band')->options(['A', 'B', 'C']),
                    Toggle::make('bonus_eligible')
                        ->authorize($this->role === 'admin')
                        ->authorizedUnless($this->isOwnRecord)
                        ->columnSpan(2),
                ]),
            Textarea::make('internal_notes')->rows(2)->authorizedUnless($this->role === 'viewer'),
            Submit::make('Save employee'),
        ];
    }
}

// In your app: EmployeeForm::make($request->user()->role, $employee->is($request->user()))
EmployeeForm::make('hr');

Methods ​

All three methods accept a bool or a Closure. They are available on fields, fieldsets, and the form.

MethodPasses when
authorize($check)the check is truthy
authorizedWhen($check)the check is truthy (alias of authorize())
authorizedUnless($check)the check is falsy
php
TextInput::make('internal_notes')->authorizedWhen($user->isStaff());

Toggle::make('featured')->authorizedUnless(fn () => $user->isGuest());

A closure receives the item it belongs to (the field, fieldset, or form) and is evaluated when the form is serialized or validated.

You can call these methods more than once. Every check must pass.

php
Combobox::make('owner_id')
    ->authorize(fn () => auth()->check())
    ->authorize(fn () => auth()->user()->can('reassign', Post::class));

Fields and fieldsets ​

An unauthorized field or fieldset is removed everywhere:

  • it is not in the serialized schema,
  • it has no initial value in data(),
  • it gets no validation rules, so any submitted value is ignored by validated(),
  • getField('name') returns null.
php
Fieldset::make('Admin')
    ->authorize(fn () => auth()->user()->isAdmin())
    ->fields([
        Toggle::make('is_verified'),
        Combobox::make('plan')->options(Plan::class),
    ]);

The whole form ​

Call the methods on the form instance, or inside your class (for example in the constructor):

php
return Inertia::render('Settings/Billing', [
    'form' => BillingForm::make()->authorize($request->user()->can('update-billing')),
]);

When the whole form is unauthorized:

  • Serialization returns an empty form: no fieldsets, no data, and action set to null. The frontend renders nothing but the default submit button, and submitting does nothing because there is no action.
  • Validation with validate() or #[Validate] throws an AuthorizationException (HTTP 403).

To throw instead of returning an empty form during serialization, enable throw_on_unauthorized in the config:

php
// config/inertia-forms.php
'throw_on_unauthorized' => true,

Authorizing inside the class ​

Because the check is evaluated late, you can keep authorization inside fields():

php
class PostForm extends Form
{
    public function fields(): array
    {
        return [
            TextInput::make('title')->required(),
            Toggle::make('pinned')->authorize(fn () => auth()->user()?->can('pin', Post::class) ?? false),
            Submit::make('Save'),
        ];
    }
}