# 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