Using the Have I Been Pwned API

';--have i been pwned? is the gold standard for seeing if a user's account has been compromised in a data breach. This is usually done using an eMail address, which is what I'll be demonstrating here.

I will be using the Have I Been Pwned (HIBP) API in this notebook. The API requires a key for a nominal charge of $3.50 a month.inline_formula not implemented Obviously, my key is not available to the public.

Here's a full blog post on why ';--have i been pwned? charges for this service. The API is pretty simple, so let's get started.

Grab the Data

Use a curl command to grab the data using the API.

curl -H "hibp-api-key:$(cat /.hibp.secret)" -H "user-agent: Beyond the Frame" -sS -o "/pwned-accounts.json"
Bash in Clojure

A breakdown of the switches I used:

  • 🔑 -H "hibp-api-key:$(cat /.hibp.secret)": An HIBP subscription key is required to make an authorized call and can be obtained on the API key page. The key is then passed in a hibp-api-key header. .hibp.secret is a file used by Nextjournal to store user secrets. Replace :$(cat /.hibp.secret) with your own key.

  • -H "user-agent: Beyond the Frame": Each request to the API must be accompanied by a user agent request header. Typically this should be the name of the app consuming the service.

  • -o "/pwned-accounts.json": Output the returned JSON data.

The URL has two unique features:

  • My eMail, encoded for a URL.

  • ?truncateResponse=false: return the complete breach data for all data breaches

Examine the data returned by Have I Been Pwned:

(require '[ :as json])
(def accounts (json/read-str (slurp "/pwned-accounts.json") :key-fn keyword))
(pprint accounts)

Parse the Data

Grab three parameters from every title returned and print as HTML.

  • Title: A descriptive title for the breach suitable for displaying to end users. It's unique across all breaches but individual values may change in the future (i.e. if another breach occurs against an organisation already in the system). If a stable value is required to reference the breach, refer to the "Name" attribute instead.

  • Domain: The domain of the primary website the breach occurred on.

  • BreachDate: The date (with no time) the breach originally occurred on in ISO 8601 format. This is not always accurate — frequently breaches are discovered and reported long after the original incident. Use this attribute as a guide only.

(require '[ :as ld])
(defn account->html [account]
  (let [title (:Title account)
        link (str "<a href=\"http://" (:Domain account) "\" target=\"_blank\">"
                  title "</a>")
        date (ld/get-year (ld/parse (:BreachDate account)))]
    (str "<li>" link " in " date "</li>")))
(defn print-accounts [accounts]
  (str "<hr /><center><h2>Accounts Associated With This eMail</h2><br /><ul>"
     (apply str (map #(account->html %) accounts))
       "</ul></center><br /><br /><hr />"))
{:nextjournal/viewer "html" 
 :nextjournal.viewer/value (print-accounts accounts)}

That's it. Use your key and simply replace the eMail address with any other eMail address and you will get the pertinent results.


inline_formula not implementedThe language of HIBP's API is not very clear. If you cancel your subscription, your API key will remain functional until the subscription renewal is due after which it will cease to work. You can always reactivate it by returning to the API key page and purchasing another one.

Have I Been Pwned is the source of the data on this page. Some of the writing is directly cut from their API v3 documentation, also under CC4.0.

 {org.clojure/clojure {:mvn/version "1.10.0"}
  {:git/url ""
   :sha "f6c080bd0049211021ea59e516d1785b08302515"}
  org.clojure/data.json {:mvn/version "1.0.0"} {:mvn/version "0.1.11"}
  compliment {:mvn/version "0.3.9"}}}
Extensible Data Notation
Runtimes (1)