Generating a Security Credential
The one-time, offline step this SDK deliberately doesn't automate.
B2C Account Top Up needs a securityCredential your Initiator password, RSA-encrypted with Safaricom's public certificate, then Base64-encoded. This page walks through generating it once. This SDK does not do this step for you, on purpose.
Why this isn't automated in the SDK
Encrypting the Initiator password requires embedding Safaricom's public
certificate as a dependency a certificate that gets rotated on Safaricom's own
schedule, independent of this package's release cycle. Baking it into
@lumierelabs/daraja would mean either shipping a certificate that silently
goes stale, or adding an update mechanism that fetches and trusts a
certificate at runtime, which is a meaningfully different (and riskier)
security posture than a one-time offline step you control yourself.
Steps
Get your Initiator credentials
Your Initiator username and password are issued by Safaricom as part of your Go-Live application for B2C/B2B products not the same as your Consumer Key/Secret. In sandbox, use the shared test initiator (testapi) and its published test password from the Daraja portal's Test Credentials page.
Get Safaricom's public certificate
Sandbox and production use different certificates. Both are linked from the Daraja documentation's Test Credentials / Go-Live sections download the correct one for your target environment. Using the sandbox certificate against production (or vice versa) produces a SecurityCredential that looks structurally valid but is silently rejected by Daraja.
Encrypt the password
RSA-encrypt your Initiator password using the certificate (PKCS1 padding), then Base64-encode the result. Safaricom's Daraja documentation links an online tool for this; if you'd rather not paste a production password into a browser tool, do it locally instead:
openssl rsautl -encrypt -certin -inkey cert.cer -in password.txt | base64Where password.txt contains your raw Initiator password (no trailing newline) and cert.cer is the certificate from the previous step.
Store the result as a secret
The output is a single Base64 string this is your securityCredential. Store it as an environment variable or secret, exactly the way you'd store DARAJA_CONSUMER_SECRET. Pass it straight through to the SDK:
await daraja.b2cTopUp.topUp({
initiator: "testapi",
securityCredential: process.env.DARAJA_SECURITY_CREDENTIAL!,
// ...
});This does not need to happen per-request
securityCredential is stable until you rotate your Initiator password
generate it once and reuse it across every B2C Top Up call. Re-encrypting it
on every request (or worse, doing it inside a hot request path) adds nothing
but latency and a needless dependency on an encryption library at runtime.