# `Kinde`
[🔗](https://github.com/starfish-codes/elixir-kinde/blob/v2.1.0/lib/kinde.ex#L1)

OpenID Connect authentication with PKCE for [Kinde](https://kinde.com).

Provides two main functions:

  * `auth/2` — generates an OAuth2 authorization URL and stores the PKCE
    code verifier in state management
  * `token/4` — exchanges the authorization code for an ID token,
    verifies it, and returns user attributes

## Configuration

Required keys can be set via application config or passed directly as a map:

    config :kinde,
      domain: "https://yourapp.kinde.com",
      client_id: "client_id",
      client_secret: "client_secret",
      redirect_uri: "http://localhost:4000/callback"

When a map is passed to `auth/2` or `token/4`, its values take precedence
over the application config. See the "All configuration keys" section in
the README for a complete reference.

## Example

    # Step 1: redirect user to Kinde
    {:ok, url} = Kinde.auth()

    # Step 2: handle the callback
    {:ok, token_response, extra_params} = Kinde.token(code, state)

# `config`

```elixir
@type config() :: %{
  optional(:domain) =&gt; String.t(),
  optional(:client_id) =&gt; String.t(),
  optional(:client_secret) =&gt; String.t(),
  optional(:redirect_uri) =&gt; String.t(),
  optional(:prompt) =&gt; String.t(),
  optional(:scopes) =&gt; [String.t()]
}
```

# `state_params`

```elixir
@type state_params() :: %{code_verifier: String.t(), extra_params: map()}
```

# `token_response`

```elixir
@type token_response() :: %{
  access_token: String.t(),
  access_token_claims: map(),
  id_token: String.t(),
  id_token_claims: map(),
  refresh_token: String.t(),
  expires_in: non_neg_integer(),
  scope: String.t(),
  token_type: String.t()
}
```

# `auth`

```elixir
@spec auth(config(), map()) :: {:ok, String.t()} | {:error, term()}
```

Generates an OAuth2 authorization URL with PKCE.

Accepts an optional `config` map (overrides app env) and an optional
`extra_params` map that will be returned alongside user data after
a successful `token/4` call.

Returns `{:ok, url}` on success or `{:error, %MissingConfigError{}}` when
required configuration keys are missing.

## Examples

    iex> Kinde.auth()
    {:ok, "https://yourapp.kinde.com/oauth2/auth?..."}

    iex> Kinde.auth(%{}, %{return_to: "/dashboard"})
    {:ok, "https://yourapp.kinde.com/oauth2/auth?..."}

# `token`

```elixir
@spec token(String.t(), String.t(), config(), Keyword.t()) ::
  {:ok, token_response(), map()} | {:error, term()}
```

Exchanges an authorization code for user attributes.

Takes the `code` and `state` from the Kinde callback, verifies the ID token
via JWKS, and returns user attributes along with any `extra_params` that were
passed to `auth/2`.

Returns `{:ok, token_response, extra_params}` on success, where
`token_response` is a `t:token_response/0` map containing the full OAuth2
token endpoint response including decoded JWT claims.

## Errors

  * `{:error, %ObtainingTokenError{}}` — the token endpoint returned an error
  * `{:error, %StateNotFoundError{}}` — the state was not found (expired or already used)
  * `{:error, %MissingConfigError{}}` — required config keys are missing

---

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