# `Teac.OAuth`
[🔗](https://codeberg.org/FullStacking/teac)

Token validation and incremental authorization helpers.

## Incremental authorization

Rather than requesting every possible scope up front, incremental
authorization lets you request only the scopes a user needs for the feature
they're about to use. Twitch only shows a consent prompt for scopes not
already granted, so repeat visits feel frictionless.

### Typical flow

    # 1. Validate the user's current token to see what scopes they have.
    {:ok, token_info} = Teac.OAuth.validate_token(conn.assigns.current_user_token)

    # 2. Declare what a specific feature requires.
    required = [Teac.Scopes.Channel.moderate(), Teac.Scopes.User.read_chat()]

    # 3. Find what's missing.
    missing = Teac.OAuth.missing_scopes(token_info, required)

    # 4. If anything is missing, redirect to re-authorize with the full scope list.
    #    Twitch won't re-prompt for already-granted scopes, but the resulting
    #    token only contains what you explicitly request — so always pass all
    #    desired scopes, not just the missing ones.
    if missing != [] do
      url = Teac.OAuth.AuthorizationCodeFlow.authorize_url(scope: required)
      redirect(conn, external: url)
    end

# `missing_scopes`

```elixir
@spec missing_scopes(Teac.OAuth.TokenInfo.t(), [String.t()]) :: [String.t()]
@spec missing_scopes(String.t(), [String.t()]) ::
  {:ok, [String.t()]} | {:error, :invalid_token | term()}
```

Returns the subset of `required_scopes` not present in the token.

Accepts either a `%Teac.OAuth.TokenInfo{}` (from `validate_token/1`) or a
raw token string. When given a string, calls `validate_token/1` internally
and returns `{:error, reason}` if validation fails.

## Example

    required = [Teac.Scopes.Channel.moderate(), Teac.Scopes.User.read_chat()]

    # From a TokenInfo struct (already validated):
    [] = Teac.OAuth.missing_scopes(token_info, required)

    # From a raw token string:
    {:ok, ["channel:moderate"]} = Teac.OAuth.missing_scopes("oauth_token", required)

# `validate_token`

```elixir
@spec validate_token(String.t()) ::
  {:ok, Teac.OAuth.TokenInfo.t()} | {:error, :invalid_token | term()}
```

Validates an OAuth token and returns the scopes it currently grants.

Calls Twitch's `/oauth2/validate` endpoint. Useful for checking which
scopes a token has before deciding whether to trigger incremental auth.

Returns `{:error, :invalid_token}` when the token is expired or invalid.

## Example

    {:ok, %Teac.OAuth.TokenInfo{scopes: scopes}} = Teac.OAuth.validate_token("oauth_token_string")

---

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