# `Attesto.Did`
[🔗](https://github.com/XukuLLC/attesto/blob/v2.1.0/lib/attesto/did.ex#L1)

Connection-free resolution for self-contained DID methods.

`did:jwk` identifiers contain an unpadded base64url-encoded public JWK.
`did:key` identifiers contain a multibase/multicodec public key; this
module supports base58btc (`z`) with Ed25519 (`0xed`) and compressed P-256
(`0x1200`) keys.

`did:web` is deliberately parser-only. Without a `:resolver`, resolution
returns `{:needs_fetch, url}` so the host retains ownership of HTTP, TLS,
caching, and DID-document key selection. A resolver may instead be supplied
as `resolver: fn url -> {:ok, public_jwk} | {:error, reason} end`.

> #### `did:web` fetch URL is ATTACKER-CONTROLLED {: .warning}
>
> The `{:needs_fetch, url}` / `:resolver` URL is derived entirely from the
> presented DID text — a presenter controls it. `did:web:localhost` or
> `did:web:internal-service.corp` yield `https://localhost/.well-known/did.json`
> and the like (syntactically valid hostnames the IP-literal guard cannot
> catch). A host fetching that URL without an allow-list has an SSRF sink. Do
> NOT dereference it blindly: resolve only against a trusted-domain allow-list,
> and use a DNS-rebinding-safe fetcher that pins the validated IP (see
> `AttestoPhoenix.ClientIdMetadata.Fetcher.Req` for the reference pattern). Unlike
> `did:key`/`did:jwk`, `did:web` keys are NOT self-certifying.

# `jwk`

```elixir
@type jwk() :: %{required(String.t()) =&gt; term()}
```

# `result`

```elixir
@type result() :: {:ok, jwk()} | {:needs_fetch, String.t()} | {:error, term()}
```

# `resolve`

```elixir
@spec resolve(term(), term()) :: result()
```

Resolve a `did:jwk` or `did:key` to a public JWK, or parse a `did:web`
identifier into its HTTPS resolution URL.

This function never performs network I/O. If `:resolver` is supplied for a
`did:web`, it is called with the parsed HTTPS URL and must return either a
public JWK map or an error tuple.

---

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