# A person the app has not seen

The first time someone signs in whom your app has no user for, Jadpo
asks your app what to do. `on_first_sign_in:` in `authentication { }`
names the action that decides: create a user, link one that already
exists, or refuse. One action decides for every way in.

It runs when:

- a magic link or code is used for an address no user has;
- a provider returns an account not yet linked to a user;
- an external token names a subject not yet linked to a user.

Here the action refuses an address Google hasn't verified, and creates a
member otherwise:

```jadpo
// domains/accounts/actions/create_member.jadpo
action create_member(first: FirstSignIn) fails SignUpClosed -> Member.id {
    if (first.method == SignInMethod.google and not first.address_verified) {
        reject SignUpClosed
    }
    var member: Member = attempt Member.create(...)
    return member.id
}
```

| `FirstSignIn` field | Type | Holds |
|---|---|---|
| `method` | `SignInMethod` | The way in: `magic_link`, each provider named under `sign_in:`, or `external_token`; a built-in enum with one value per way the app declares |
| `address` | `Email?` | For a magic link, the address, verified; for a provider, its email claim; for an external token, none |
| `address_verified` | `Bool` | `true` for a magic link; the provider's own verified claim for a provider; `false` for an external token |
| `subject` | `Text?` | The provider's or token's subject; none for a magic link |
| `name` | `Text?` | The display name a provider's profile gives, when it gives one |

- The action takes exactly one `FirstSignIn` and returns the `id` of the
  principal's user entity: a user it created, or one that already exists.
  It runs in its own transaction before the session starts.
- To refuse, it fails with any failure it declares. The person always
  sees the same built-in `sign_in_refused`, whatever the reason. The log
  and the `SignInRefused` event keep the real one.
- For a provider or an external token, Jadpo then records the link, from
  the method and subject to the user's `id`, in the `jadpo_sign_in_links`
  system table, so the next sign-in skips the action. A magic link needs
  no link: Jadpo finds the user by `address:`.
- Linking a user who already exists, by their address, is the action's
  choice. Do it only when `address_verified` is `true`, so no one can
  take over an account by claiming its address at a provider that doesn't
  check it.
- Without `on_first_sign_in:`, only users who already exist sign in. An
  unknown address gets no email, and an unknown provider account or token
  subject is `sign_in_refused`.
- A passkey never runs it. Only a person already signed in can add a
  passkey, so every passkey that signs in has its user.

Not built yet: `on_first_sign_in:` for provider and external-token sign-in.
An external token whose subject no user has is `sign_in_refused` (403).
