Cocoa brownies

Cocoa brownies are pretty magical, i.e. particularly good at staying soft and gooey, and Alice Medrich's ingredient list is nearly flawless. (Okay, okay, I can never truly stick to a recipe as written. Here, I prefer a little more vanilla extract and like to put a pinch of flaky sea salt on top just before baking for bursts of salty goodness.) But I find the listed prep a little too intensive to do as regularly as I like to make brownies - who really wants to deal with a double boiler to melt the butter along with the cocoa, sugar, and salt? Isn't a large part of the appeal of using cocoa that you don't have to fuss as much with heating ingredients because you're not worried about burning chocolate?

A double batch of cocoa brownies in a 13x9-inch pan sitting on a stovetop

I simplified the prep and didn't notice a difference in the final product. (Okay, I admit I didn't do a double blind brownie tasting study, but I'd like to think I have a fairly discriminating palate when it comes to brownies.) Sometimes I use weight measurements, but since brownies are forgiving, I usually default to using volume measurements. Sometimes I use unsalted butter like Medrich's original recipe calls for, but more often, I don't have it on hand and use the salted butter I have and skip the salt in the batter. You could add 2/3 cup of chopped nuts after stirring in the flour if you want, but since one of my closest friends is allergic and he's often over to help consume my baked goods, I haven't done this yet.

Alice Medrich's cocoa brownies, simplified


  • 10 tablespoons (140 grams) unsalted or salted butter
  • 1 1/4 cups (250 grams) white granulated sugar
  • 3/4 cups + 2 tablespoons (80 grams) unsweetened cocoa powder (natural cocoa powder makes fudgier brownies than Dutch-process - honestly, I usually use Nestle Toll House Baking Cocoa)
  • 1/4 teaspoon Kosher salt if using unsalted butter
  • 1 teaspoon vanilla extract
  • 2 large eggs
  • 1/2 cup (65 grams) bread or all-purpose flour (you don't really need to sift it or use weight measurements with something as forgiving as brownies, but don't pack it tightly)
  • A pinch or two of flaky sea salt (I use Maldon) to top


  1. Preheat the oven to 325 degrees F and place a rack in the middle of the oven.
  2. Butter an 8-inch square baking pan (or just spray it with cooking oil). If you're doubling the recipe, use a 13x9-inch pan.
  3. Melt the butter. (I usually do this in a microwave on medium power.) Pour it into a large mixing bowl. (You may be tempted to melt the butter in your mixing bowl if it's microwave safe. Resist this temptation because you don't want the eggs to cook because the bowl is hot when you add them a couple steps later.)
  4. Stir in the sugar with a spatula.
  5. Stir in the cocoa powder and salt.
  6. Stir in the vanilla extract.
  7. Crack the eggs into the bowl, break their yolks with the spatula, and stir them into the batter.
  8. Stir in the flour until combined. The mixture might be a bit gritty, but this is normal.
  9. Spread mixture into the pan - you will probably need to smush it down with the spatula.
  10. Sprinkle the top with flaky sea salt.
  11. Bake until a toothpick comes out only slightly moist, about 20 to 25 minutes. (If you are using convection, it will likely be more like 18 to 20 minutes.)
  12. Let cool, cut, and enjoy!

Yields about 16 very rich and delightful brownies. Total preparation time is about 35 minutes.

New Loose Leaf Security series: all about phone security

Two more episodes of Loose Leaf Security are out, a series about phone security:

A locked phone by a teacup

Securing your phone

We take our phones everywhere and trust them with a lot of sensitive information, but have we put enough thought into how to secure them? Liz and Geoffrey discuss different aspects of securing the smartphone you have, including passcodes, location services, notifications, and digital voice assistants. Plus, a question from a caller and a major Supreme Court decision!

A two-tiered cake stand: the top tier has Android and Apple logo frosted cookies, the bottom tier has various tea sandwiches

Comparing Android and iOS security

Considering buying a new phone? Liz and Geoffrey compare the different security models of Android and iOS, the two most popular smartphone options on the market. We also talk about California's new privacy law, a number of recent attacks on cell phones, and how Tinder swiped left on bad crypto.

Head over to Loose Leaf Security or click the links above for the full audio and our detailed show notes. As a reminder, you can subscribe to Loose Leaf Security in your favorite podcatcher or follow the project on Twitter, Instagram, and Facebook.

New Loose Leaf Security episode: two-factor authentication and account recovery

The second episode of Loose Leaf Security came out today, about two-factor authentication and account recovery:

A hardware security key with a leaf logo on a keychain near the spout of a steaming pot of tea

Two-factor authentication and account recovery

Last time we talked about strong passwords, but what if there was a better way to secure your account? We look at options for two-factor authentication, including text messages, apps, and security keys. Plus, security news from Apple, one of Liz's accounts got breached, and Geoffrey wants to celebrate a special birthday.

Head over to Loose Leaf Security for the full audio, show notes - including a deep dive into different two-factor authentication methods and which ones are supported by a handful of popular websites - and complete transcript. As a reminder, you can subscribe to Loose Leaf Security in your favorite podcatcher or follow the project on Twitter, Instagram, and Facebook.

Introducing Loose Leaf Security, and securing your online account passwords

I just launched a new project with Geoffrey Thomas: Loose Leaf Security, a podcast about making good computer security for everyone. We believe you don't need to be a software engineer or security professional to understand how to keep your devices and data safe. In every episode, we tackle a typical security concern or walk you through a recent incident.

Loose Leaf Security album cover

Our first episode is about securing your online account passwords:

A password made up of letters, numbers, and symbols written in the steam of a green lock-inspired teapot

Securing your online account passwords

You've heard for years about how to come up with strong passwords, but are those guidelines really true? Liz and Geoffrey talk about new risks to your online accounts, especially with the news of clear-text passwords being mishandled at Twitter and GitHub, and whether you should trust a password manager to solve all your password problems for you. Plus, what's happening to the green lock icon in Chrome, and should you worry about EFAIL?

The full audio, show notes - including a comprehensive and current comparison of the leading password managers - and complete transcript can be found on our new website. You can also catch our show on Apple Podcasts, Google Play, Pocket Casts, Stitcher, TuneIn, or other podcast places. Sadly, we're not yet in Spotify, but we're working on it! We're now on Spotify, too! Additionally, you can follow the project on Twitter, Instagram, and Facebook.

Adding Open Graph to Pelican

I just added Open Graph support to this Pelican-generated site so pretty previews would show up when people shared my posts, and I figured I'd share the fairly tidy way I went about it in case other people were interested. I only added support for articles, my journal entries, and pages, the other headers on this site, because adding it for things like tags didn't make a lot of sense (why would anyone share those?).

The changes were pretty simple. First, I added the following to the <head> section of template.html, the part of my custom theme from which every webpage on my site inherits its style:

{% if article is defined %}
<meta property="og:type" content="article" />
<meta property="og:url" content="{{ SITEURL }}/{{ article.url }}" />
<meta property="og:title" content="{{ article.title | replace("\"", "&quot;") }}" />
<meta property="og:description" content="{{ article.content | striptags | replace("\"", "&quot;") | truncate(196, False, '...') }}" />
<meta property="og:image" content="{{ SITEURL }}/images/{% if article.opengraph_image is defined %}{{ article.opengraph_image }}{% else %}opengraph-default.jpg{% endif %}" />
{% elif page is defined %}
<meta property="og:type" content="website" />
<meta property="og:url" content="{{ SITEURL }}/{{ page.url }}" />
<meta property="og:title" content="{{ SITENAME }} - {{ page.title | replace("\"", "&quot;") }}" />
<meta property="og:description" content="{{ page.content | striptags | replace("\"", "&quot;") | truncate(196, False, '...') }}" />
<meta property="og:image" content="{{ SITEURL }}/images/{% if page.opengraph_image is defined %}{{ page.opengraph_image }}{% else %}opengraph-default.jpg{% endif %}" />
{% else %}
<meta property="og:type" content="website" />
<meta property="og:url" content="{{ SITEURL }}/{{ output_file }}" />
<meta property="og:title" content="{{ SITENAME }}" />
<meta property="og:description" content="A page on Liz Denys's personal site" />
<meta property="og:image" content="{{ SITEURL }}/images/opengraph-default.jpg" />
{% endif %}

It was obvious to treat what Pelican calls articles, my journal/blog entries, as articles, and I decided to treat my Pelican pages, basic information about me, as websites. My article titles stand well on their own, but my page titles are accompanied by Liz Denys, my SITENAME, because they don't make as much sense on their own. Everything else - my journal's timeline and tag pages - doesn't have a lot of information in Pelican, so they just got a boring default.

Raw double quotes would be problematic in meta tags, so I make sure to replace them with the friendlier HTML entity &quot; in both the titles and descriptions with Jinja's replace function. I've found that double quotes in article titles mess other things up in Pelican, but still applied the replace to titles here just in case that changes.

The Open Graph description property, og:description, is generally a preview of the website's content, and since I don't use Pelican's summary attributes in my theme, I opted to grab a bit of the content directly with article.content or page.content. I couldn't find a definitive answer as to how much that should be - Open Graph says a description is "a one to two sentence description of your object", Facebook defines a description as "a clear description, at least two sentences long", and Twitter specifies that a description has a maximum of 200 characters. These seemed a bit conflicting, so I followed the clearest instruction, Twitter's, and limited my descriptions to 200 characters, including the possible trailing " ..." with Jinja's truncate function.

Some, but not all, of my articles and pages contain images, so I wanted a default og:image for the entire site that could get overridden on webpages where something specific made more sense. I briefly considered progamatically taking the first image to appear in a post for its preview, but when I looked through some older posts, I noticed this wasn't always the right choice both in terms of content and size - you need at least a 200px square for Facebook and probably want even larger. I uploaded a default og:image to "{{ SITEURL }}/images/opengraph-default.jpg". I named the file that instead of something that describes its content (currently an old photo of me in SIPB's machine room) so that I would only need to upload a new image to the same location to change it later. When I want to override this default for an article or page, I'd simply define opengraph_image in the meta information of its Markdown file like so:

Title: Inbox by Gmail's accidentally abusive algorithm
Slug: inboxs-accidentally-abusive-algorithm
Date: 2016-05-14 11:03
Tags: a little too helpful; content algorithms; email; gmail; Google; harassment; inbox; product design
opengraph_image: software/inboxs-accidentally-abusive-algorithm/inbox-speed-dial.jpg

The code in the template checks whether or not this meta information exists, so if I want to use the site default, I simply leave it out.

Once I added this to my site, I checked that my new Open Graph information rendered as I expected with Facebook's Sharing Debugger and Twitter's Card Validator. I also sent direct messages containing links to my posts on Slack to see how they rendered there with the new Open Graph information. Here's what one of my articles now looks like when someone posts it to Facebook:

Facebook share preview for Inbox by Gmail's speed dial with Open Graph information including an image, title, and description

That same article when it's shared on Twitter:

Twitter card preview for Inbox by Gmail's speed dial with Open Graph information including an image, title, and description

And finally, what it looks like when posted to Slack:

Slack preview for Inbox by Gmail's speed dial with Open Graph information including an image, title, and description