# Security.Authorize — does THIS person satisfy a policy

> `Security.Authorize(person, Policy)` answers whether a given person satisfies a declared policy — evaluated exactly as it is for a request of theirs, never as the caller. One yes or no about one person; it grants nothing. What a kit asks to find "the leads" or "the reviewers" without knowing how the app decides who they are.

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

## Summary        {#summary}
A `policy` is a question about the caller. Sometimes you need its answer about somebody else — who on a list is a lead,
whom to tell. Ask it of them:

```osy syntax
if (Security.Authorize(member, LeadsInbox)) { leads.Add(member); }
```

## Signature      {#signature}
```osy syntax
bool Security.Authorize(Principal person, PolicyName)            // a policy that takes no argument, named bare
bool Security.Authorize(Principal person, PolicyName(argument))  // a parameterised one, with its argument
// person: the principal row, or its id
```

## Description    {#description}

### Whose answer   {#whose}
The person's. The policy is evaluated with THEM as `user` — their account and their roles, the way a request of
theirs is armed — so a workflow body (which reads everything) and an admin's request get the same answer as anybody
else would about that person. An id that is nobody answers **false**, never what an anonymous visitor would be granted.
It is the same evaluation `[Authorize(PolicyName)]` and `if (PolicyName)` use for the caller, so a policy means one thing
in all three places.

### It grants nothing   {#grants-nothing}
It answers one yes or no about one person, and nothing else. Nothing runs as them, nothing is written as them, nothing
they could read is handed back, and the caller's own access is untouched: asking whether somebody is a lead does not
make the caller one — the next line's `if (IsLead)` and every row rule still answer for the caller.

### Only a policy you can see   {#which-policies}
The second argument NAMES a declared policy; it is not a condition to evaluate. It must be one this code can see — the
app's own, or (in a kit) one the kit declares, or a package it uses declares. A kit therefore asks only about a rule the
app was handed and filled in — `policy LeadsInbox;` in the kit, `policy LeadsInbox => IsLead;` in the app — and never
about the app's other rules. Anything else is a compile error that lists every policy there is to name:

```osy syntax
Security.Authorize(m, IsLeed)          // there is no `policy IsLeed` this code can see — the policies this code can name: …
Security.Authorize(m, m.Grade == 1)    // the second argument names a policy; it is not a condition to evaluate
Security.Authorize(m, IsAuthenticated) // `IsAuthenticated` is the platform's own state of a caller, not a declared policy
```

### In a kit   {#in-a-kit}
This is how a kit reaches "the people the app says" without knowing the app's roles. The WorkQueues kit declares who leads
it as a policy the app supplies, and finds a queue's leads by asking it of each member:

```osy syntax
// in the kit
policy LeadsInbox;
public List<Principal> InboxLeads(WorkItem item) {
  List<Principal> leads = [];
  foreach (var m in QueueMember.Where(m => m.Queue == item.Queue && m.Active).Include(m => m.Member).ToList()) {
    if (Security.Authorize(m.Member, LeadsInbox)) { leads.Add(m.Member); }
  }
  return leads;
}
// in the app — the only thing it writes about its leads
policy LeadsInbox => IsLead;
```

### What it costs   {#cost}
One evaluation per person asked: their principal and roles (kept between requests, as a request's are) and whatever
the policy itself reads. Ask it of the people a decision is about — a queue's members — not of every account.

## Examples       {#examples}
```osy title="who on the rota leads the wards" test app=security-authorize
enum Grade { Lead, Nurse }

[Principal] entity Carer {
  [MaxLength(100)] string Name = "";
  security { allow read, create when IsAnonymous || IsAuthenticated; }
}

entity Grading {
  [Required] Carer Who;
  [Required] Grade Grade;
  security { allow read, create when IsAnonymous || IsAuthenticated; }
}

entity Ward {
  [Required, MaxLength(40)] string Name;
  Carer? Head;
  security { allow read, create when IsAnonymous || IsAuthenticated; }
}

policy LeadsWards => Grading.Any(g => g.Who == user && g.Grade == Grade.Lead);
policy Heads(Ward w) => w.Head == user;

/// The leads on the rota — asked of each carer, by the app's own rule, whoever is asking.
List<string> LeadsOnTheRota() {
  List<string> leads = [];
  foreach (var c in Carer.OrderBy(c => c.Name).ToList()) {
    if (Security.Authorize(c, LeadsWards)) { leads.Add(c.Name); }
  }
  return leads;
}

/// Whether `carer` heads `ward` — a parameterised policy, with its argument.
bool HeadsIt(Carer carer, Ward ward) { return Security.Authorize(carer, Heads(ward)); }
```

## See also       {#see-also}
- [policy](https://osysharp.com/reference/security/naming-a-policy/) — declaring a policy, and asking it of the caller
- [Security.MayRead — may THIS person read this row, under their own rules](https://osysharp.com/reference/security/may-read/) — the same idea for a row: may THIS person read it
- [security { }](https://osysharp.com/reference/security/entity-security/) — the rules a policy is used in
- [Inbox.Notifications — the people the inbox names, told in their bell](https://osysharp.com/reference/workflow/inbox-notifications-kit/) — a queue's leads told, by the app's `LeadsInbox`
