# Session.CurrentUser

> `Session.CurrentUser` is the person the app is being shown to, as your own `[Principal]` entity. Read it in a member, in a render expression, or straight inside an action — the compiler puts the read where it belongs, so `Owner = Session.CurrentUser` in a Save button means what it looks like it means. A single scalar of it (`Session.CurrentUser.Email`, `.Id`) costs no round trip at all. It is null for a visitor who has not signed in.

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

## Signature      {#signature}
```osy syntax
Session.CurrentUser          // your [Principal] entity — the signed-in person. Null when nobody is.
Session.CurrentUser.Email    // any SCALAR of theirs — resolved in place, no round trip
Session.SignOut()            // the other end of the session — drops the ticket, back to the login page
```

Available in every component, with no `using`. Requires the app to declare a `[Principal]` entity.

## Summary        {#summary}
`Session.CurrentUser` is the signed-in principal — a row of whatever entity your app marked `[Principal]`, with the
fields you declared on it. It is **null when nobody is signed in**, which is the honest answer and the reason a page
that needs a user should say so with routing rather than by checking here.

You can read it in any of the three places a component holds a value, and you do not have to know which:

- as a **member** — `var me = Session.CurrentUser;` — the whole row, fetched when the page loads;
- in a **render expression** — `Text(Session.CurrentUser.Email)`;
- inside an **action** — `new Order { Reference = reference, Owner = Session.CurrentUser };`

The third one is the one that used to need a workaround. It does not any more: the compiler hoists the read onto the
component and the action closes over it, which is precisely what you would have written by hand.

## Description    {#description}

### Reading a single field costs nothing        {#scalars}
A scalar of the principal — `Session.CurrentUser.Email`, `.Id`, or any column you declared — resolves **in place, on
whichever side is asking**, with no round trip. The browser reads it from the bag the server sent at boot, built
server-side, so a field your security rules mask reads null in the browser exactly as it does on the server. Use it
freely in a render expression, a filter, or a field default:

```osy syntax
Text($"Signed in as {Session.CurrentUser.Email}");
live var mine = Order.Where(o => o.Owner.Id == Session.CurrentUser.Id);
```

Reaching **through** a reference (`Session.CurrentUser.Manager.Name`) is a different question — the browser holds the
manager as an id, not as a row — so that stays a server read and belongs on a member.

### The whole row, in an action        {#in-an-action}
An action runs in the browser, and the browser cannot run a database read in the middle of one. So when an action
mentions `Session.CurrentUser`, the compiler lifts the read onto the component as an ordinary fetched member and the
action reads that. Several actions on one page share one fetch.

```osy test app=ui-current-user
[Principal] entity User {
  [Required, MaxLength(200)] string Email;
  security { allow read when IsAuthenticated; }
}

entity Order {
  [Required, MaxLength(50)] string Reference;
  User Owner;
  security { allow read, create when IsAuthenticated; }
}

[Page("/orders/new")]
[Render(CSR)]
component NewOrder() {
  string reference = "";

  action Save() {
    new Order { Reference = reference, Owner = Session.CurrentUser };
    UnitOfWork.Commit();
  }

  render {
    Stack {
      Input(value: reference, placeholder: "Reference");
      Pressable(onClick: Save) { Text("Save"); }
    }
  }
}
```

⚠ **Other reads behave differently inside an action, and it is worth knowing which.** An ordinary read —
`Order.Where(…)` — is **not yet available inside an action**: bind it to a member and read the member instead. The
browser has no database, so a read in the middle of an action means a round trip at that moment; the compiler does not
yet arrange one. `Session.CurrentUser` needs no such arrangement — its value is fixed for as long as the page is open
(signing in or out reloads the app), so it is fetched with the page and simply read.

### It is who is being SHOWN the page, not who wrote the row        {#versus-audit}
Every entity is audited automatically, and `CreatedBy` on a saved row is stamped **by the server** from the request's
principal. Your own field (`Owner` above) is the app's view; the audit column is the platform's, and no app code can
write it. When you want proof of who did something, read the audit column. When you want a relationship you control —
who a task is assigned to, whose basket this is — declare your own reference and set it.

### Nobody is signed in        {#anonymous}
`Session.CurrentUser` is null for an anonymous visitor. Do not use that null as a gate: a page that requires a user
should require one at the route (routed components are protected unless they say `[AllowAnonymous]`), so the page is
never rendered for someone who is not there. If you want a name for work done *before* sign-in, that is
[Visitor](https://osysharp.com/reference/ui/visitor/).

## See also       {#see-also}
- [Visitor](https://osysharp.com/reference/ui/visitor/) — the anonymous twin, for work that begins before there is a user
- [component](https://osysharp.com/reference/ui/component/) — members, actions, and where each kind of value lives
- [[security-auth-bootstrap#sign-out]] — `Session.SignOut()`, the verb that ENDS the session this page reads
- [principal predicates (IsAuthenticated / IsAnonymous) and open reads](https://osysharp.com/reference/security/principal-predicates/) — the predicates that read the same principal in a `security { }` block
