# `Exgit.Credentials`
[🔗](https://github.com/ivarvong/exgit/blob/v0.1.0/lib/exgit/credentials.ex#L1)

Helpers for constructing transport auth values, plus a small
host-scoped credential mechanism.

The flat constructors (`basic/2`, `bearer/1`) return raw auth tuples
suitable for `Exgit.Transport.HTTP.new/2` — callers who know exactly
which URL they're talking to typically use these directly.

`host_bound/2` and `for_host/2` add a safety rail: a credential is
only surrendered when the target URL's host matches the bound
pattern. This guards against accidentally leaking a GitHub token to
an attacker-controlled redirect, a CI misconfiguration, or a user-
supplied URL that points somewhere unexpected.

## Host matching

`for_host/2` normalizes the URL's host before comparing it against
the pattern:

  * case-folded via `String.downcase/1` (ASCII only — we refuse to
    recognize tokens for a Unicode TLD; IDN hosts must be supplied
    in punycode)
  * trailing `.` (DNS fully-qualified form) stripped
  * Unicode/IDN hosts are NOT normalized — callers who need IDN
    matching must provide the punycode host explicitly

Patterns:

  * Exact hostname: `"github.com"` matches only `github.com`
    (case-insensitive).
  * Wildcard: `"*.githubusercontent.com"` matches
    `githubusercontent.com` AND any `x.githubusercontent.com`. A
    single-component wildcard label is required — the pattern must
    start with `*.`.

No regex, no substring matching, no glob.

# `auth`

```elixir
@type auth() :: Exgit.Transport.HTTP.auth_value()
```

# `host_cred`

```elixir
@type host_cred() :: %Exgit.Credentials{auth: auth(), host_pattern: String.t() | :any}
```

# `t`

```elixir
@type t() :: host_cred()
```

# `basic`

```elixir
@spec basic(String.t(), String.t()) :: auth()
```

# `bearer`

```elixir
@spec bearer(String.t()) :: auth()
```

# `bind_to`

```elixir
@spec bind_to(auth() | host_cred(), String.t()) :: host_cred()
```

Rewrap an existing host-bound credential to bind to `pattern`. Useful
in a pipeline:

    Credentials.bearer(token) |> Credentials.bind_to("github.com")

If the input is a bare auth tuple, `bind_to/2` wraps it in a fresh
`%Credentials{}`. If it's already a `%Credentials{}` struct, the
existing `auth` is reused with the new pattern.

# `for_host`

```elixir
@spec for_host(host_cred(), String.t()) :: {:ok, auth()} | :none
```

Return the auth value iff the credential's host binding matches the
given URL. Returns `:none` otherwise.

# `host_bound`

```elixir
@spec host_bound(String.t(), auth()) :: host_cred()
```

Wrap an auth value with a host pattern. The pattern is either a bare
hostname (`"github.com"`) or a wildcard (`"*.githubusercontent.com"`).
Use `for_host/2` to extract the auth when (and only when) the URL
matches.

# `unbound`

```elixir
@spec unbound(auth()) :: host_cred()
```

Wrap an auth value without a host binding. Emits the auth for any
URL — caller has explicitly opted out of scoping.

---

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