<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/a-reasonably-practical-guide-to-validating-rfc-9421-http-signatures-for-activitypub-in-php-jlxhqlzoq" -->

---
title: A reasonably practical guide to validating RFC 9421 HTTP...
description: A practical, code-heavy walkthrough of validating RFC 9421 HTTP Message Signatures as sent by Mastodon and other Fediverse servers implementing ActivityPub,...
canonical: https://daily.dev/posts/a-reasonably-practical-guide-to-validating-rfc-9421-http-signatures-for-activitypub-in-php-jlxhqlzoq
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: A reasonably practical guide to validating RFC 9421 HTTP Signatures for ActivityPub in PHP | daily.dev
og:description: A practical, code-heavy walkthrough of validating RFC 9421 HTTP Message Signatures as sent by Mastodon and other Fediverse servers implementing ActivityPub,...
og:url: https://daily.dev/posts/a-reasonably-practical-guide-to-validating-rfc-9421-http-signatures-for-activitypub-in-php-jlxhqlzoq
og:image: https://api.daily.dev/og/posts/jLXhqlzoQ.png
og:image:alt: A reasonably practical guide to validating RFC 9421 HTTP Signatures for ActivityPub in PHP
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# A reasonably practical guide to validating RFC 9421 HTTP Signatures for ActivityPub in PHP

**[Terence Eden](https://daily.dev/sources/shkspr)** · 6 min read · 0 upvotes · 0 comments

## Summary

A practical, code-heavy walkthrough of validating RFC 9421 HTTP Message Signatures as sent by Mastodon and other Fediverse servers implementing ActivityPub, written in PHP. Covers verifying the content-digest header, constructing the Signature Base from the signature-input header, fetching the sender's public key from their ActivityPub actor document, and using openssl_verify() to confirm authenticity. Includes a full working PHP code example and a step-by-step checklist, plus links to further reading on RFC 9421.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://shkspr.mobi/blog/2026/09/a-reasonably-practical-guide-to-validating-rfc-9421-http-signatures-for-activitypub-in-php>

## Questions this post answers

### How do I verify an RFC 9421 HTTP Message Signature sent by Mastodon in PHP?

Use openssl_verify() with the SHA256 algorithm against a Signature Base string constructed from the signed components. Extract the content-digest, signature, and signature-input headers, rebuild the Signature Base by concatenating each covered component (like @method, @target-uri, content-digest) followed by @signature-params, fetch the sender's publicKeyPem from their ActivityPub actor document via the keyid URL, then call openssl_verify() with the base64-decoded signature and that public key.

_Developers implementing federated protocols can track PHP and security how-tos like this on daily.dev._

### How do I validate the content-digest header on an incoming ActivityPub request before checking the signature?

Compute a base64-encoded SHA256 hash of the raw request body and compare it against the value in the content-digest header before trusting the message. Split the header on the first equals sign to get the algorithm name and expected hash, strip the colons around the hash, then use PHP's hash() function with binary output and base64_encode() to compute your own value; if it doesn't match, reject the request.

_daily.dev helps developers verifying federated protocol payloads stay current on RFC 9421 implementation details._

### Does Mastodon always use SHA256 for HTTP message signatures?

Yes, Mastodon's implementation of HTTP message signatures only uses SHA256, even though its documentation does not explicitly state which algorithm is used. This was flagged as an issue on Mastodon's GitHub repository, since RFC 9421 supports multiple signature algorithms and relying implementations need to know which one to expect.

_Fediverse developers debugging signature mismatches can follow protocol clarifications like this on daily.dev._

## Similar posts on daily.dev

- [Book Review: ActivityPub by Evan Prodromou](https://daily.dev/posts/book-review-activitypub-by-evan-prodromou-dpy4t8tac) · Terence Eden · 2 upvotes · 1 comments
- [ActivityPub - Is it worth defending against replay attacks and message/signature time skew?](https://daily.dev/posts/activitypub---is-it-worth-defending-against-replay-attacks-and-message-signature-time-skew--fq3lj7mfw) · Terence Eden · 0 upvotes · 0 comments
- [Why implementing ActivityPub is hard, and why it doesn't have to be](https://daily.dev/posts/why-implementing-activitypub-is-hard-and-why-it-doesn-t-have-to-be-uc9l3hqnb) · Lobsters · 0 upvotes · 1 comments

---

Tags: [#php](https://daily.dev/tags/php), [#cryptography](https://daily.dev/tags/cryptography), [#mastodon](https://daily.dev/tags/mastodon), [#activitypub](https://daily.dev/tags/activitypub)

[View this post on daily.dev](https://daily.dev/posts/a-reasonably-practical-guide-to-validating-rfc-9421-http-signatures-for-activitypub-in-php-jlxhqlzoq)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"A reasonably practical guide to validating RFC 9421 HTTP Signatures for ActivityPub in PHP","url":"https://daily.dev/posts/a-reasonably-practical-guide-to-validating-rfc-9421-http-signatures-for-activitypub-in-php-jlxhqlzoq","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/a-reasonably-practical-guide-to-validating-rfc-9421-http-signatures-for-activitypub-in-php-jlxhqlzoq"},"datePublished":"2026-09-03T11:39:22.659Z","dateModified":"2026-09-03T11:39:52.490Z","description":"A practical, code-heavy walkthrough of validating RFC 9421 HTTP Message Signatures as sent by Mastodon and other Fediverse servers implementing ActivityPub,...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/58746186467abf171fe31177a0ca8f37?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/58746186467abf171fe31177a0ca8f37?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Terence Eden","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Terence Eden","logo":"https://media.daily.dev/image/upload/s--nhylgPuf--/f_auto,q_auto/v1774964413/logos/shkspr?_a=BAMAMiWQ0","url":"https://daily.dev/sources/shkspr"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/a-reasonably-practical-guide-to-validating-rfc-9421-http-signatures-for-activitypub-in-php-jlxhqlzoq","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"php,cryptography,mastodon,activitypub","timeRequired":"PT6M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Terence Eden","item":"https://daily.dev/sources/shkspr"},{"@type":"ListItem","position":3,"name":"A reasonably practical guide to validating RFC 9421 HTTP Signatures for ActivityPub in PHP"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/a-reasonably-practical-guide-to-validating-rfc-9421-http-signatures-for-activitypub-in-php-jlxhqlzoq#faq","mainEntity":[{"@type":"Question","name":"How do I verify an RFC 9421 HTTP Message Signature sent by Mastodon in PHP?","acceptedAnswer":{"@type":"Answer","text":"Use openssl_verify() with the SHA256 algorithm against a Signature Base string constructed from the signed components. Extract the content-digest, signature, and signature-input headers, rebuild the Signature Base by concatenating each covered component (like @method, @target-uri, content-digest) followed by @signature-params, fetch the sender's publicKeyPem from their ActivityPub actor document via the keyid URL, then call openssl_verify() with the base64-decoded signature and that public key. Developers implementing federated protocols can track PHP and security how-tos like this on daily.dev."}},{"@type":"Question","name":"How do I validate the content-digest header on an incoming ActivityPub request before checking the signature?","acceptedAnswer":{"@type":"Answer","text":"Compute a base64-encoded SHA256 hash of the raw request body and compare it against the value in the content-digest header before trusting the message. Split the header on the first equals sign to get the algorithm name and expected hash, strip the colons around the hash, then use PHP's hash() function with binary output and base64_encode() to compute your own value; if it doesn't match, reject the request. daily.dev helps developers verifying federated protocol payloads stay current on RFC 9421 implementation details."}},{"@type":"Question","name":"Does Mastodon always use SHA256 for HTTP message signatures?","acceptedAnswer":{"@type":"Answer","text":"Yes, Mastodon's implementation of HTTP message signatures only uses SHA256, even though its documentation does not explicitly state which algorithm is used. This was flagged as an issue on Mastodon's GitHub repository, since RFC 9421 supports multiple signature algorithms and relying implementations need to know which one to expect. Fediverse developers debugging signature mismatches can follow protocol clarifications like this on daily.dev."}}]}
```

