# `Daraja.SecurityCredential`
[🔗](https://github.com/okothkongo/daraja/blob/v0.1.1/lib/daraja/security_credential.ex#L1)

Utilities for building Daraja security credentials.

Safaricom expects the initiator password encrypted with the portal-provided
certificate/public key and Base64 encoded. Used by B2B and B2C `PaymentRequest`
modules; also callable directly.

Download the encryption certificate from the
[Daraja developer portal](https://developer.safaricom.co.ke) only.

## Pinning trusted certificates

When `:security_credential_pins` is set, PEM inputs must match a configured
SPKI SHA-256 fingerprint before encryption:

    config :daraja,
      environment: :production,
      security_credential_pins: ["yGsAE85gJh3satQK/3DRqZCjovsVGOqmUQ22wXvoIko"]

Generate a pin from a portal certificate with `spki_fingerprint/1`.

Pinning is skipped when the list is empty. In `:sandbox`, set
`:enforce_security_credential_pins` to `false` to disable pinning during
local development. Production always enforces when pins are configured.

## Tuple credentials (`{password, pem}`)

Tuple inputs are encrypted on first use and cached in `:persistent_term`.
For production, pre-encrypt at deploy time and pass only the Base64 string.

Disable tuple credentials in production:

    config :daraja,
      environment: :production,
      allow_tuple_security_credential: false

A one-time warning is logged when tuples are used (disable with
`:warn_tuple_security_credential: false`).

# `encrypt_error`

```elixir
@type encrypt_error() ::
  :invalid_public_key
  | :encryption_failed
  | :untrusted_public_key
  | :tuple_credentials_disabled
```

# `encrypt`

```elixir
@spec encrypt(String.t(), String.t()) :: {:ok, String.t()} | {:error, encrypt_error()}
```

Encrypts a plaintext initiator password using the provided PEM certificate or
PEM public key and returns a Base64 encoded security credential.

# `resolve`

```elixir
@spec resolve(String.t() | {String.t(), String.t()} | nil | term()) ::
  {:ok, String.t() | nil} | {:error, encrypt_error() | :invalid_format}
```

Resolves a `security_credential` input to an encrypted Base64 string.

Accepts:
- A pre-encrypted Base64 string — returned as-is.
- A `{password, pem}` tuple — encrypts using `encrypt/2`.
- `nil` — returned as `{:ok, nil}` so the missing-field check in
  `PaymentRequest.new/1` can report it normally.
- Any other value — returns `{:error, :invalid_format}`.

# `spki_fingerprint`

```elixir
@spec spki_fingerprint(String.t()) ::
  {:ok, String.t()} | {:error, :invalid_public_key}
```

Returns the SHA-256 SPKI fingerprint (Base64) for a PEM certificate or public key.

Use the value in `:security_credential_pins`.

---

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