# [Authorize] on an action

> `[Authorize]` on one action (or method) of a component makes that action members-only, on any page — a public `[AllowAnonymous]` page included. A caller who is not signed in (or, with `[Authorize(Policy)]`, does not satisfy the policy) is not shown the controls that run it, and the server refuses to run it for them. The rest of the page is unchanged. It is ASP.NET's `[Authorize]` on one action of an anonymous controller.

<!-- id: ui-authorize-action · area: ui · stability: stable · html: https://osysharp.com/reference/ui/authorize-action/ -->

## Summary        {#summary}
A public page often has one or two things only a signed-in visitor may do — **Add to order**, **Message the
seller**, **Book**. Put `[Authorize]` on the action that does it:

```osy syntax
[Route("/wines")] [AllowAnonymous]
component Wines() {
  [Authorize] action Add(Wine w) { AddToOrder(w); }             // any signed-in caller
  [Authorize(Sommeliers)] action Taste(Wine w) { BookTasting(w); } // a declared policy
  render { … Button("Add to order", onPress: () => Add(w)); … }
}
```

Everyone sees the catalogue. Only a signed-in visitor sees the **Add to order** button, and only someone who
satisfies `Sommeliers` sees **Book a tasting**. Everyone else sees nothing where those buttons sit — no disabled
button, no error.

## Signature      {#signature}
```osy syntax
[Authorize] action Name(<params>) { … }            // any signed-in caller
[Authorize(Policy)] action Name(<params>) { … }    // a signed-in caller who satisfies the declared `policy`
[Authorize(Policy)] <Type> Name(<params>) { … }    // the same on a component method
```
- **`Policy`** — a declared, no-argument `policy` (see [page authorization (policies)](https://osysharp.com/reference/ui/authorize/)). It is checked like any other policy
  reference: a name that is not declared is a compile error. Because the page decides whether to show the button
  from the policy, it must be one a control can reflect — the same rule as `canSee:` ([canPress / canEdit / canSee](https://osysharp.com/reference/ui/policy-controls/)).
- **Bare `[Authorize]`** means "anyone signed in". `[Authorize(IsAuthenticated)]` says the same thing out loud.

## Description    {#description}
`[Authorize]` on an action does two things, and you need both:

- **The page does not show it.** Any control whose event runs the action — `onPress: Add`, `onPress: () => Add(w)` —
  is rendered only for a caller who passes the gate. The smallest element that names the action is the one hidden,
  so a `Stack` around the button stays. Reading the action's `.Pending` flag (a busy label) does not count as running
  it.
- **The server does not run it.** Every server call the action makes — and its `UnitOfWork.Commit()` — is refused for
  a caller who does not pass the gate, whatever the browser sends. A signed-out visitor is told to sign in; a signed-in
  caller without the policy is told their account does not satisfy it. Nothing in the action runs.

This is how the members-only **component** behaves too (`[Authorize(Policy)] component …` placed on a public page — see
[page authorization (policies)](https://osysharp.com/reference/ui/authorize/)); the attribute on the action saves moving the button and its action into a component of their own.

The functions the action calls keep their own access rules. `[Authorize]` on the action decides who may run the
**action**; a caller who skips the page and names a server function directly meets that function's own grant. So a
public page can leave `AddToOrder` gated, as every function is unless marked `[AllowAnonymous]`, and the compiler no
longer refuses the page for calling it — the action that calls it is now a signed-in caller's action.

### Who may call a gated action     {#callers}
The server knows a click by the action the control ran. So an action that RUNS a gated one must carry the **same**
`[Authorize]` — otherwise the gated body would run under the ungated action's name — and this is a compile error. An
`on mount` hook, an `on change` block or a field cannot carry a gate at all, so they cannot run a gated action; a
gated action runs from a control. An inline handler (`onPress: () => { Add(w); }`) takes the gate of the action it
runs; one handler cannot run two actions with different gates.

## Examples       {#examples}
A public wine list. Anyone can browse; a signed-in buyer can add a wine to their order; a sommelier can book a
tasting. `AddToOrder` stays an ordinary, gated server function.

```osy title="a public catalogue with members-only actions" test app=ui-authorize-action
[Principal] entity Buyer {
  [Unique, MaxLength(200)] string Email;
  security { allow read when IsAuthenticated; }
}
[Role] enum Level { Buyer, Sommelier }
[RoleGrant] entity Grant {
  [Required("Who the grant is for is required.")] Buyer Holder;
  Level Level;
  security { allow read when IsAuthenticated; }
}
policy Sommeliers => Grant.Any(g => g.Holder == user && g.Level == Level.Sommelier);

entity Wine {
  [Required("A wine needs a name."), MaxLength(80)] string Name;
  security { allow read when IsAuthenticated || IsAnonymous; }
}
entity OrderLine {
  [Required("Which wine is required."), MaxLength(80)] string Wine;
  security { allow read, create when IsAuthenticated; }
}

void AddToOrder(string wine) { new OrderLine { Wine = wine }; UnitOfWork.Commit(); }

[Route("/wines")]
[Title("Wines")]
[AllowAnonymous]
[Render(CSR)]
component Wines() {
  live var wines = Wine.Take(50).ToList();
  [Authorize] action Add(string name) { AddToOrder(name); }
  [Authorize(Sommeliers)] action Taste(string name) { AddToOrder("tasting: " + name); }
  render {
    Stack {
      foreach (var w in wines) {
        Text(w.Name);
        Button("Add to order", onPress: () => Add(w.Name));      // signed-in buyers only
        Button("Book a tasting", onPress: () => Taste(w.Name));  // sommeliers only
      }
    }
  }
}
```

## See also       {#see-also}
- [page authorization (policies)](https://osysharp.com/reference/ui/authorize/) — policies, `[Authorize(Policy)]` on a page, and the members-only component
- [canPress / canEdit / canSee](https://osysharp.com/reference/ui/policy-controls/) — `canSee:`/`canPress:`: reflect a policy on a control without gating an action
- [routes and pages](https://osysharp.com/reference/ui/routing/) — protected-by-default pages and `[AllowAnonymous]`
- [Session.CurrentUser](https://osysharp.com/reference/ui/current-user/) — who is signed in, from a component
