README.md

# ExKeychain

Elixir bindings to macOS Keychain Services via Security.framework.

Uses [Rustler](https://github.com/rusterlium/rustler) NIFs backed by the
[security-framework](https://crates.io/crates/security-framework) Rust crate
(146M+ downloads, used by `reqwest` and `rustls`).

## Installation

```elixir
def deps do
  [{:ex_keychain, "~> 0.1.0"}]
end
```

Requires Rust toolchain (`rustup`). macOS only.

## Usage

```elixir
# Store a password
:ok = ExKeychain.set("my-app", "user@example.com", "s3cret")

# Retrieve it
{:ok, "s3cret"} = ExKeychain.get("my-app", "user@example.com")

# Check existence without triggering access dialogs
true = ExKeychain.exists?("my-app", "user@example.com")

# List all accounts for a service
["user@example.com"] = ExKeychain.list("my-app")

# Delete
:ok = ExKeychain.delete("my-app", "user@example.com")
```

## How It Works

All keychain operations go through Apple's Security.framework C API
(`SecItemAdd`, `SecItemCopyMatching`, `SecItemUpdate`, `SecItemDelete`).
The Rust layer provides safe wrappers and handles CoreFoundation type
conversion. Rustler handles the Erlang NIF machinery.

All NIF functions are scheduled on dirty I/O schedulers since keychain
operations involve IPC with the `securityd` daemon.

## Code Signing

Some keychain operations (especially on the system keychain or with
access control lists) require code signing. For development, a
self-signed certificate works. For distribution, use a proper
Developer ID certificate.

## License

MIT