ActivityPub uses authentication for two purposes; first, to authenticate clients to servers, and second, in federated implementations, to authenticate servers to each other.
ActivityPub uses authorization to check that activities' actors are not spoofed and that objects are only modified by the actor(s) who own them.
ActivityPub's core specification does not specify official mechanisms for either authentication or authorization, but the community has converged on some common practices.
Client to Server
ActivityPub clients authenticate against a server using OAuth 2.0 bearer tokens.
Bearer tokens may be acquired out of band. They may also be acquired using OAuth 2.0 authorization. To discover the correct endpoint for authorization, clients should use OAuth-Server-Metadata on the host part from the actor's ID URI.
Client IDs may be acquired out of band for some servers. They may also be acquired using RFC7591.
Server to Server
Signing requests using HTTP Signatures
Server to server federation via inbox delivery POST requests is authenticated using HTTP Signatures in conjunction with the signing key from the actor's publicKey field. The keyId should link to the actor so that the publicKey field can be retrieved. At minimum, the digest field should be included in the set of headers being signed.
Most servers generally require incoming inbox delivery requests to include HTTP Signatures.
Some servers have a feature called authorized fetch, aka secure mode, which requires all HTTP GET requests for ActivityPub objects to include HTTP Signatures. This is intended to increase the server's control over who can access its data. From Mastodon's documentation:
As a result, through the authentication mechanism and avoiding re-distribution mechanisms that do not have your server in the loop, it becomes possible to enforce who can and cannot retrieve even public content from your server, e.g. servers whose domains you have blocked.
Servers with authorized fetch enabled generally don't enforce any fine grained access control over the actors whose signatures they require to fetch data. They usually only reject requests from actors on domains that they've blocked at the server level. (This means that the name authorized fetch is maybe partially a misnomer, and something like signed fetch might be more appropriate.)
One consequence of authorized fetch is that signed fetches can end up in a kind of deadlock or infinite loop. If server
a.example fetches https://b.example/bob with https://a.example/alice's signature, and
b.example doesn't have alice's public key, it will get it by fetching https://a.example/alice with https://b.example/bob's signature.
a.example won't have bob's public key either, so it will again try to fetch https://b.example/bob, and the cycle will continue.
To prevent this, servers with authorized fetch enabled often use an instance actor to sign object fetches. This is generally a "server-level" actor, separate from any normal user, that doesn't require an HTTP Signature to be fetched. This breaks the loop of fetching each actor back and forth to validate their signatures.
Data integrity proofs / Linked Data Signatures
For most forms of delivery, HTTP Signatures are enough. However, some objects may be passed around the network, whether being shared, forwarded, or otherwise referenced at a future time. In this case it is important to be able to verify that the actors specified in the actor and attributedTo fields really did author the objects they are being claimed to have authored. In such a case we need to be able to verify the integrity of the object being passed around, and so we must sign the object itself.
For this we use data integrity proofs (FEP-8b32) or Linked Data Signatures (obsolete but more common) to sign the object with the publicKey of the actor that is the actor or attributedTo of the object being passed around the network.
Once a client or server has authenticated, ie proven which actor they're acting on behalf of, servers should also authorize their activities and objects by checking that they're allowed to send them.
As with authentication, the ActivityPub and ActivityStreams 2.0 specs leave authorization mostly unspecified. Even so, a few common authorization practices have emerged in ActivityPub implementations.
Activities that create or modify an object - Create, Update, Delete, Undo, Move, etc - must be the same actor as the original object's attributedTo or activity's actor. This is generally called the "same origin policy."
(Confusingly, web browsers have a related but different same origin policy for comparing URLs that ignores path and query parameters, and the ActivityPub spec seems to mix these definitions. For example, 7.1 Delivery seems to use the web browser definition, while 7.3 Update seems to use it to mean object ownership.)
Activities must be authenticated by their actor. In the common case of HTTP Signatures, this is just a simple check that the inbox delivery request is signed by the activity's actor. However, not all deliveries can be signed by their actor. Notably, in inbox forwarding, the sending server doesn't have access to the activity actor's private key.
In those cases, if the activity includes a data integrity proof or Linked Data Signature, it can be verified and checked against activity's actor. Otherwise, if the activity's id is on the same server (ie web browser origin) as the actor, the receiving server may choose to refetch the activity from its source. This foregoes verifying a signature by an actor in exchange for trusting its server, which is consistent with the current real world ActivityPub security model of custodial keys and trusted servers.
Typically, addressees for an object or an activity have read-only access to the object or activity. This includes actors that are members of a collection (such as a list, a group, a followers or following collection) that is addressed in the
It is OK to test membership of a collection at read time; it's not necessary to confirm that the actor was a member of the collection at send time. So, for example, if
email@example.com sends a note to her followers, and
firstname.lastname@example.org is following her at send time, and later unfollows her, it is OK for a processor to keep Bob from reading the note.
Per Activity Pub spec, Activities addressed to this special URI [Public] shall be accessible to all users, without authentication. Any content that includes 'Public' in its addressing properties (to, cc, audience, bto, bcc) should be readable by anyone on the Internet, even unauthenticated users.
Blocking features, as well as API security features, may make this functionally less open than defined in the spec. For example, a server may have IP addresses blocked for misbehaviour, in which case the request will fail.
Also see the authorized fetch mode that some servers offer, which requires authentication for any GET request for an Activity Streams 2.0 object.
Only authenticated users
ActivityPub does not have an access level defined for only authenticated users.
Here are excerpts from the ActivityPub and ActivityStreams 2.0 specifications that reference authorization.
The receiving server MUST take care to be sure that the Update is authorized to modify its object. At minimum, this may be done by ensuring that the Update and its object are of same origin.
The side effect of receiving this is that (assuming the object is owned by the sending actor / server) ...
Servers should not trust client submitted content, and federated servers also should not trust content received from a server other than the content's origin without some form of verification.
Servers should be careful to verify that new content is really posted by the actor that claims to be posting it, and that the actor has permission to update the resources it claims to.
ActivityStreams 2.0 Core
Consumers should be aware of the potential for spoofing attacks where the attacker publishes activities or objects with falsified property values with the intent of injecting malicious content, hiding or corrupting legitimate content, or misleading users.