# `Ltix.OAuth`
[🔗](https://github.com/DecoyLex/ltix/blob/main/lib/ltix/oauth.ex#L1)

OAuth 2.0 client credentials authentication for LTI Advantage services.

Acquires an access token from the platform's token endpoint and returns
an authenticated `Ltix.OAuth.Client` ready for service calls.

## From a launch context

    {:ok, client} = Ltix.OAuth.authenticate(launch_context,
      services: [Ltix.MembershipsService, MyApp.AttendanceService]
    )

## From a registration

    {:ok, client} = Ltix.OAuth.authenticate(registration,
      endpoints: %{
        Ltix.MembershipsService => memberships_endpoint,
        Ltix.GradeService => ags_endpoint
      }
    )

A token request from a launch context includes the launch's deployment ID. With a registration, pass `:deployment` to include one. A platform may require it before it issues a token.

    {:ok, client} = Ltix.OAuth.authenticate(registration,
      endpoints: %{Ltix.GradeService => ags_endpoint},
      deployment: deployment
    )

The platform may grant only some of the scopes the endpoints need. Each service operation returns a `Ltix.Errors.Invalid.ScopeMismatch` error when its scope was not granted. Pass `require_all_scopes: true` to get that error from `authenticate/2`.

## Options (launch context)

* `:services` (list of `t:atom/0`) - Required. Service modules whose endpoints are read from the launch claims.

* `:req_options` (`t:keyword/0`) - Options passed through to `Req.request/2`. The default value is `[]`.

* `:local_network_access` (`nil` | `:none` | `:local` | `:loopback`) - Addresses platform requests may connect to besides public ones. `:local`
  adds private network addresses, and `:loopback` adds those and this
  machine. Defaults to `config :ltix, :local_network_access`, then `:none`.

* `:storage_adapter` (`t:module/0`) - Module implementing `Ltix.StorageAdapter`, which signs token requests. Defaults to the application configuration.

* `:storage_adapter_options` (`t:keyword/0`) - Options passed to the storage adapter's signing callbacks. The default value is `[]`.

* `:require_all_scopes` (`t:boolean/0`) - Return a `ScopeMismatch` error unless every scope the endpoints need was granted. The default value is `false`.

## Options (registration)

* `:endpoints` (`t:map/0`) - Required. Map of service modules to endpoint structs.

* `:deployment` (`t:term/0`) - The deployment the token is for, as a struct implementing `Ltix.Deployable` or a deployment ID. Token requests include it.

* `:req_options` (`t:keyword/0`) - Options passed through to `Req.request/2`. The default value is `[]`.

* `:local_network_access` (`nil` | `:none` | `:local` | `:loopback`) - Addresses platform requests may connect to besides public ones. `:local`
  adds private network addresses, and `:loopback` adds those and this
  machine. Defaults to `config :ltix, :local_network_access`, then `:none`.

* `:storage_adapter` (`t:module/0`) - Module implementing `Ltix.StorageAdapter`, which signs token requests. Defaults to the application configuration.

* `:storage_adapter_options` (`t:keyword/0`) - Options passed to the storage adapter's signing callbacks. The default value is `[]`.

* `:require_all_scopes` (`t:boolean/0`) - Return a `ScopeMismatch` error unless every scope the endpoints need was granted. The default value is `false`.

# `authenticate`

```elixir
@spec authenticate(Ltix.LaunchContext.t() | Ltix.Registerable.t(), keyword()) ::
  {:ok, Ltix.OAuth.Client.t()} | {:error, Exception.t()}
```

Authenticate with a platform's token endpoint.

Accepts a `%LaunchContext{}` or any struct implementing `Ltix.Registerable`,
including `Ltix.Registration` itself. With a launch context, list the
services in the `:services` option, and Ltix reads each endpoint from the
launch claims. With a registration, pass the endpoints in the `:endpoints` option.
A service missing from the launch returns a `ServiceNotAvailable` error.

# `authenticate!`

```elixir
@spec authenticate!(Ltix.LaunchContext.t() | Ltix.Registerable.t(), keyword()) ::
  Ltix.OAuth.Client.t()
```

Same as `authenticate/2` but raises on error.

---

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