# `MishkaCmsCore.Accounts.SignInProvider`
[🔗](https://github.com/mishka-group/mishka_cms_core/blob/v0.0.1/lib/mishka_cms_core/accounts/sign_in_provider.ex#L5)

Signing in with another service's account as `mishka_installer` plugins on `"auth:providers"`,
the way `MishkaCmsCore.Captcha.Provider` makes captchas. The core names no provider: each ships as
its own package (`mishka_cms_auth_google`, `mishka_cms_auth_github`, …) whose application starts
its plugin, so a host that adds the dependency has the provider on every site's Security tab.

AshAuthentication does the sign-in itself, through one strategy for every provider
(`MishkaCmsCore.Accounts.ProviderStrategy`: `/api/auth/user/provider/<id>/request`, and one
callback for all, `/api/auth/user/provider/callback`). A plugin
says which Assent strategy speaks to its provider (`c:oauth/0`) — Assent knows each provider's
addresses and how its answer reads — and adds what differs per site: its keys, whether the site
offers it, and its button. Every account a provider signs in keeps one
`MishkaCmsCore.Accounts.UserIdentity` for it, named `"provider/<id>"`.

A site that has not switched the provider on, has no keys for it, or whose provider plugin is
stopped refuses it before the visitor is sent anywhere.

## Settings

The Security tab's "Sign-in methods" table: each provider switched on per site
(`auth.providers.<id>.enabled`) with its keys in its row, and `auth.social.register`, whether a
first sign-in makes an account. A master signs in on the master site's address with the master
site's providers. The address each provider sends the visitor back to is `callback_url/1`, which
its console has to list.

    use MishkaCmsCore.Accounts.SignInProvider,
      id: "github", label: gettext_noop("GitHub"), priority: 20

    @impl true
    def oauth, do: %{assent: Assent.Strategy.Github}

# `site_id`

```elixir
@type site_id() :: String.t() | nil
```

# `icon`

```elixir
@callback icon() :: %{path: String.t(), color: String.t()}
```

The button's mark: an SVG path in a 24×24 box, and its Tailwind text colour.

# `id`

```elixir
@callback id() :: String.t()
```

The provider's id, in its route and its setting keys: `"github"`.

# `label`

```elixir
@callback label() :: String.t()
```

The name on the button and the settings page, as a `gettext_noop/1` msgid.

# `oauth`

```elixir
@callback oauth() :: %{:assent =&gt; module(), optional(atom()) =&gt; term()}
```

How it signs in: `:assent`, the Assent strategy that speaks to the provider
(`Assent.Strategy.Github`, or `Assent.Strategy.OAuth2` / `Assent.Strategy.OIDC` with its addresses
for one Assent does not name), and any `MishkaCmsCore.Accounts.ProviderStrategy` field set over
Assent's own defaults for it — `base_url`, `authorize_url`, `token_url`, `user_url`,
`authorization_params`, and `code_verifier: true` for PKCE (S256) where the provider takes it.

# `offered?`
*optional* 

```elixir
@callback offered?() :: boolean()
```

Whether the provider is offered on this installation. Every provider is, unless it says not.

# `ready?`

```elixir
@callback ready?(site_id()) :: boolean()
```

Whether `site_id` holds every key the provider needs.

# `secret`

```elixir
@callback secret(name :: atom(), site_id()) :: {:ok, String.t()} | :error
```

One of its keys for `site_id`: `:client_id` or `:client_secret`.

# `settings`

```elixir
@callback settings() :: [MishkaCmsCore.Settings.definition()]
```

The provider's own key fields (`MishkaCmsCore.Settings.define/3`).

# `all`

```elixir
@spec all() :: [module()]
```

Every registered provider module, the first of each id.

# `available`

```elixir
@spec available(site_id()) :: [module()]
```

The providers `site_id` offers, in the installation's order: the buttons its sign-in pages draw.

# `callback_url`

```elixir
@spec callback_url(%{host: String.t()}) :: String.t()
```

The address a provider sends a visitor back to on `site`, which its console has to list: the
callback every provider shares, on the site's own address, read from the site record.

    SignInProvider.callback_url(site) #=> "https://example.com/api/auth/user/provider/callback"

# `enabled_key`

```elixir
@spec enabled_key(module() | String.t()) :: String.t()
```

The setting that switches `provider` on for a site.

# `event`

```elixir
@spec event() :: String.t()
```

`"auth:providers"`: a provider plugin adds itself to the `providers` list it carries.

# `fetch`

```elixir
@spec fetch(String.t() | nil) ::
  {:ok, module()} | {:error, :unknown_provider | :cannot_run}
```

The offered provider registered under `id`.

# `key`

```elixir
@spec key(String.t(), atom(), String.t(), keyword()) ::
  MishkaCmsCore.Settings.definition()
```

A provider's key field: a `:string` (or `type`) setting on the Security tab that each site sets for
itself, drawn in the provider's own row of the "Sign-in methods" table while it is on. `opts` are `MishkaCmsCore.Settings.define/3`'s.

# `methods_group`

```elixir
@spec methods_group() :: String.t()
```

The Security tab's group every way of signing in is switched in.

# `offered`

```elixir
@spec offered() :: [module()]
```

The providers this installation offers.

# `on?`

```elixir
@spec on?(module(), site_id()) :: boolean()
```

Whether `site_id` offers `provider`: switched on, with every key it needs.

# `own`

```elixir
@spec own(String.t(), site_id()) :: String.t() | nil
```

A site's own value of a provider setting, trimmed; `nil` when it set none.

# `register?`

```elixir
@spec register?(site_id()) :: boolean()
```

Whether a first sign-in with a provider on `site_id` makes an account there.

# `settings`

```elixir
@spec settings() :: [MishkaCmsCore.Settings.definition()]
```

The rows of the Security tab's "Sign-in methods" table that are about providers — one switch per
provider and whether a first sign-in makes an account — then each provider's keys, drawn while its
switch is on. Part of `MishkaCmsCore.Settings`' core definitions.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
