The ActivityPub protocol is a social networking protocol based upon the ActivityStreams 2.0 data format. It is based upon experience gained from implementing and working with the OStatus and Pump.io protocols.

This document is a proposed submission to the W3C Social working group.

Overview

The ActivityPub protocol is broadly based on the distribution of activities, described using [[!ActivityStreams]]; these activities are produced in response to a user performing an activity. Most activities are purely responsive in nature - they are produced as a response to a user having done something. In addition, certain activities posted by a user to their outbox may trigger certain operations on the user's behalf. Finally, activities may have side effects as they propogate throughout the social graph. As an example of this:

  1. A user posts the like activity to their outbox. This activity causes the user's server to perform an activity on behalf of the user; in particular, it adds the specified object to the collection of objects the user has liked.
  2. A consequence of the above activity (per ) is that the server hosting the liked object will be notified of the operation, and will normally add the activity to the list of "likes" the object has received.
  3. Finally, the server receiving the like will distribute this activity to everyone it distributed the original object to.

Specification Profiles

This specification defines two closely related and interacting protocols:

A client to server protocol, or "Social API"
This protocol permits a client to act on behalf of a user. For example, this protocol is used by a mobile phone application to interact with the user's social stream.
A server to server protocol, or "Federation Protocol"
This protocol is used to distribute activities between users on different servers, tying them into one social graph.

All servers claiming conformance to this specification are required to implement the former protocol, and may optionally implement the latter. This gives three conformance classes:

ActivityPub conformant Client
This designation applies to any implementation of the entirety of the client portion of the client to server protocol.
ActivityPub conformant Server
This designation applies to any implementation of the entirety of the server portion of the client to server protocol.
ActivityPub conformant Federated Server
This designation applies to any implementation of the entirety of the server portion of both the client to server and federation protocols.

It is called out whenever a portion of the specification only applies to implementation of the federation protocol. In addition, whenever requirements are specified, it is called out whether they apply to the client or server (for the client-to-server protocol) or which of a pair of servers in the server-to-server protocol.

Objects

Objects are the core concept around which both [[!ActivityStreams]] and ActivityPub are built. Objects are often wrapped in Activities and are contained in streams of Collections, which are themselves subclasses of Objects. See the ActivityStreams Vocabulary document, particularly the Core Classes, to get a sense of how this lays out; ActivityPub follows the mapping of this vocabulary very closely.

Servers SHOULD validate the content they receive to avoid content spoofing attacks. In particular, 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. The general mechanism that is specified for this at this time is for a recipient of some referenced activitystreams object to verify the presence of that object on the original server. Other mechanisms such as verifying signatures are left out of scope of this document. (However, if other generally agreed upon mechanisms for handling verification become available in the future, servers are welcome to use those methods, in the future.)

As an example, if example.com receives the activity
         {
           "type": "Like",
           "actor": "https://example.net/~mallory",
           "to": ["https://hatchat.example/sarah/",
                  "https://example.com/peeps/john/"],
           "object": {
             "id": "https://example.org/~alice/note/23",
             "type": "Note",
             "author": "https://example.org/~alice",
             "content": "I'm a goat"
           }
         }
        
it should dereference the id both to ensure that it exists and is a valid object, and that it is not misrepresenting the object. (In this example, Mallory could be spoofing an object allegedly posted by Alice.)
Mention requirement of JSON-LD @context

Object Identifiers

All Objects in [[!ActivityStreams]] should have unique global identifiers. ActivityPub extends this requirement; all objects distributed by the ActivityPub protocol MUST have unique global identifiers; these identifiers must fall into one of the following groups:

  1. Publicly dereferencable URIs, such as HTTPS URIs, with their authority belonging to that of their originating server. (Publicly facing content SHOULD use HTTPS URIs.)
  2. An ID explicitly specified as the JSON null object, which implies an anonymous object (a part of its parent context)

Identifiers MUST be provided for activities posted in server to server communication. However, for client to server communication, a server receiving an object with no specified id should allocate an object ID in the user's namespace and attach it to the posted object.

All objects must have the following properties:

id
The object's unique global identifier
type
The type of the object

Methods on objects

The HTTP GET method may be dereferenced against an object's id property to retrieve the activity. Servers MAY use HTTP content negotiation as defined in [[!RFC7231]] to select the type of data to return in response to a request. The client MUST specify an Accept header, this specification only applies in the selection of the application/activity+json media type.

Servers MAY implement other behavior for requests which do not comply with the above requirement. (For example, servers may implement additional legacy protocols, or may use the same URI for both HTML and ActivityStreams representations of a resource)

Servers MAY require authorization as specified in , and may additionally implement their own authentication rules. Servers SHOULD fail requests which do not pass their authorization or authentication checks with the appropriate HTTP error code, or the 404 Not Found error code where the existence of the object is considered private.

The GET method

The HTTP GET method shall return an up-to-date version of the object.

Actors

Actors in ActivityPub are represented by HTTP URI. When entered directly into a user interface (for example on a login form), it is desirable to support simplified naming. For this purpose cases, ID normalization SHOULD be performed as follows:

  1. If the entered ID is a valid URI, then it is to be used directly.
  2. Otherwise, the entered value should be considered invalid.
How to normalize entries without URI scheme, e.g. tantek.com

Once the actor's URI has been identified, it should be dereferenced.

Actor objects

Actor objects are ActivityStreams objects which are subclasses of the actor type. Actor objects MUST have, in addition to the properties mandated by , the following properties:

inbox
A reference to an [[!ActivityStreams]] collection comprising of all the messages received by the actor; see .
outbox
An [[!ActivityStreams]] collection comprising of all the messages produced by the actor; see .

Implementations SHOULD, in addition, provide the following properties:

url
A link to the actor's "profile web page", if it is not equal to the value of id.
following
An [[!ActivityStreams]] collection of the actors that this actor is following.
followers
An [[!ActivityStreams]] collection of the actors that follow this actor.
name
The preferred "nickname" or "display name" of the actor.
mediaEndpoint
Upload endpoint URI for this user for binary data.
          {
            "@context": [
              "http://www.w3.org/ns/activitystreams",
              "http://www.w3.org/ns/activitypub"
            ],
            "type": "Person",
            "id": "https://johnsmith.example.com/",
            "following": "https://johnsmith.example.com/following.json",
            "followers": "https://johnsmith.example.com/followers.json",
            "inbox": "https://johnsmith.example.com/inbox.json",
            "outbox": "https://johnsmith.example.com/feed.json",
            "preferredUsername": "johnsmith",
            "name": "John Smith",
            "summary": "Just an example guy",
            "icon": [
              "https://johnsmith.example.com/image/165987aklre4"
            ]
          }
        

Implementations MAY, in addition, provide the following properties:

streams
A list of supplementary Collections which may be of interest.
preferredUsername
A short username which may be used to refer to the actor, with no uniqueness guarantees.
summary
A quick summary or bio by the user about themself.
icon
A media link to the user's profile picture (this may be a thumbnail).

Authorization

This is a stub, to be expanded. OAuth 2.0 is an open question.

ActivityPub uses authorization for two purposes; first, to authenticate clients to servers, and secondly in federated implementations to authenticate servers to each other. These methods are based upon the OAuth 2.0 authorization framework as specified in [[!RFC6749]].

User Authentication

User authentication is used in order to identify clients acting on behalf of an actor their origin server, and for federated implementations to other servers. There are two types of authentication permitted for this:

Bearer Authorization

For clients which only need to interact with the user's origin server, or communicating with a non-federated server, clients may use OAuth 2.0 bearer tokens.

JSON Web Signature authorization

This method is only mandatory for federated implementations

For clients which need to interact with servers beyond the user's origin server, clients MUST support use of OAuth 2.0 with JSON Web Signatures.

Origin Authorization

This method is only applicable to federated implementations

A server performing an operation on behalf of an actor (e.g. delivery to a recipient) must authenticate itself with the 3rd party server as such. One method for doing so is defined in this specification.

JSON Web Signature authorization

Servers MUST support use of OAuth 2.0 with JSON Web Signatures.

Endpoint Discovery

When a user dereferences an actor's ID the page MUST contain HTML script element with the type attribute set to application/ld+json.

        
      

Collections and Streams

[[!ActivityStreams]] defines the collection concept; ActivityPub defines several collections with special behavior. Additionally, it defines a subset of collections termed streams.

Followers Collection

Every actor MUST have a followers collection. This is a list of everyone who has sent a Follow activity for the user. This is where one would find a list of all the users that are following the actor.

The follow activity generally is a request to see the objects a user creates, this would make the "followers" collection a good default collection to provide to the user when selecting the audience targeting.

Following Collection

Every actor MAY have a following collection. This is a list of everybody that the actor has followed.

Likes Collection

Every actor MAY have a likes collection. This is a list of every object that the actor has marked as having liked. (See the Like activity.)

Streams

Streams are collections of ActivityStreams objects, generally Activities, which are always presented in reverse chronological order.

Outbox

The outbox stream contains objects the user has published, subject to the ability of the requestor to retrieve the object (that is, the contents of the outbox are filtered by the permissions of the person reading it). If a user submits a request without Authorization the server should respond with all of the Public posts. This could potentially be all relevant objects published by the user, though the number of available items is left to the descretion of those implementing and deploying the server.

A client may submit an [[!ActivityStreams]] activity to the server using a HTTP POST request to the dereferencable URI of the outbox collection. In this case, the request's Content-Type MUST be application/activity+json, and the request MUST be authenticated with credentials authorized to act on behalf of the user to whom the outbox belongs. Such submitted activities will be added to the front of the feed retrieved by GET requests to the same endpoint.

Inbox

The inbox stream contains all objects received by the user. The server SHOULD filter content according to the requester's permission. In general, the owner of an inbox is likely to be able to access all of their inbox whereas depending on access control, some other content may be public, whereas other content may require authentication for non-owner users, if they can access the inbox at all.

A server may submit a HTTP POST to the dereferencable URI of the inbox endpoint. This request MUST be authenticated with the credentials of the user identified by the actor stanza of the activity being delivered. The request MUST be of the [[!ActivityStreams]] content type; it MUST be a single activity. The incoming activity MUST have a valid URI as its id. The server MUST ensure the validity of the posted and any enclosed objects (generally by dereferencing the object on the originating server.)

The server MUST perform de-duplication of activities, whereby it discards repeats of already delivered activities (this can occur if an activity is addressed both to a user's followers, and a specific user which happens to follow said user, and the server has failed to de-duplicate the recipients list, for example). Such deduplication MUST be performed by comparing the id of the activities and dropping any activities already seen.

Targeting and Delivery of notifications

In order to propagate updates throughout the social graph, Activities are sent to the appropriate recipients. First, these recipients are determined through following the appropriate links between objects until you reach an agent (targeting), and then the Activity is inserted into the agent's inbox (delivery). This allows recipient servers to:

Delivery is usually triggered by, for example:

Targeting

Primary targeting is per the audience targetting properties from the [[!ActivityStreams]] specification. Notification targeting ensures the owners of all linked objects are notified of a new Activity that relates to them. Thus, the target(s) for final delivery of an Activity are:

  • Primary targeting: the values of the to, cc or bcc fields (likely to include the followers collection)
  • Notification targeting: the actors for all objects in the object, target or inReplyTo fields

Excluding any actors which are the same as the actor of the Activity being notified about.

If the entry is a collection, then the server MUST dereference the collection (with the user's credentials) and discover inboxes for each item in the collection. Servers MUST limit the number of layers of indirections through collections which will be performed, which MAY be one.

What to do when there are no recipients specified is not defined, however it's recommended that if no recipients are specified the object remains completely private and access controls restrict the access to object. If the object is just sent to the "public" collection the object is not delivered to any users but is publicly viewable in the actor's outbox.

Delivery

Once the target(s) for delivery have been determined, discovery of the recipient inbox(es), and delivery, are performed according to [[!LDN]].

In summary, the inbox is determined through the inbox property in the actor's profile, and an HTTP POST request (with authorization of the submitting user) is made to to the inbox, with the Activity as the body of the request. This Activity is added by the receiver as an item in the inbox Collection.

For federated servers performing delivery to a 3rd party server, delivery SHOULD be performed asynchronously to completion of the original activity submission request, and SHOULD additionally retry delivery to recipients if it fails due to network error.

Public Addressing

In addition to [[!ActivityStreams]] collections and objects, Activities may additionally be addressed to the special "public" audience denoted by the object.

          {
            "@context": "http://www.w3.org/ns/activitystreams",
            "id": "http://activityschema.org/collection/public",
            "type": "Collection"
          }
        

Activities addressed to this special URI shall be accessible to all users, without authentication.

For the purposes of delivery, the server shall treat the public collection as if it contains the same entries as the user's followers collection.

TODO: New URI? Can we get as:public in the schema or such?

Access Control

Access control is used to enforce permissions on objects; see .

Access control is largely informed by addressing and . (Implementations MAY provide additional methods of expansion or redaction of access beyond that of delivery.) Most implementations will resolve this via internally maintained access control lists. Implementations SHOULD provide initial access to recipients specified for delivery on an activity (recipients on a wrapped object however SHOULD be ignored).

Binary Data

There is the ability to submit binary data such as images, video or other binary data you wish to use in ActivityPub. This is done by means of submitting the binary data to the user's mediaEndpoint on their ActivityStreams profile object. The request MUST contain the HTTP headers Content-Type and Content-Length. A client should expect that it must be properly authenticated in order to be able to upload media. Upon successful submission a response containing the object with an ID is returned that can be posted to the users outbox.

An example response for an image I might upload is:

        {
          "@context": "",
          "id": "http://example.com/~erik/photos/1",
          "type": "Image",
          "to": ["http://example.com/~erik/public",
                 "http://example.org/~sarah/"],
          "cc": ["http://example.com/~erik/followers"],
          "url": [
            {
              "type": "Link",
              "href": "http://example.com/~erik/photos/1.png",
              "mediaType": "image/png"
            }
          ]
        }
      

Content Objects

There are objects which have a content property, the value of which is provided by the user. These can be for example note, blog, image, etc.

Reply Objects

A response can be any content object. The object MUST have an additional inReplyTo property. This property MUST have the object that your reply is in response to or the id url of the response object as a string.

          {
            "@context": "http://www.w3.org/ns/activitystreams",
            "id": "https://example.com/~alice/note/72",
            "type": "Note",
            "content": "This is a reply to a note posted by John Smith!",
            "to": ["https://example.org/~john/"],
            "cc": ["http://example.com/~erik/followers"],
            "inReplyTo": {
              "id": "https://example.org/~john/note/5",
              "type": "Note",
              "content": "Hey! This is a note in ActivityPub ^_^",
            }
          }
        
          {
            "@context": "http://www.w3.org/ns/activitystreams",
            "id": "https://example.com/~alice/note/72",
            "type": "Note",
            "content": "This is a reply to a note posted by John Smith!",
            "inReplyTo": "https://example.org/~john/note/5"
          }
        

This is only applicable to federated implementations: When a response is sent to the outbox of a user, it should be propagated to the original server that authored the object that the response is in reply to. That server should then send that response to all recipiants that the original object was sent to.

Activities

The core of any [[!ActivityStreams]] based protocol is activities within. Users post activities to their outbox, from which they are distributed to recipients' inboxes. ActivityPub places no restrictions on the activities which may be distributed; however, it defines certain activities with special behaviors

Create Activity

The Create activity is used to when posting a new object. This has the side effect that of the object that they are posting is being created. When a Create activity is posted, the actor of the activity SHOULD be copied onto the object's attributedTo field.

Object creation without a Create Activity

For client to server posting, it is possible to create a new object without a surrounding activity. The server MUST also accept a valid [[!ActivityStreams]] object that isn't a subtype of the "Activity" object being posted via a HTTP POST to the user's outbox in order to create it. The server then MUST create a wrapping Create Activity for the object. This activity then should be used in all server to server federation and throughout the Social API.

The audience is specified on the object which MUST be copied over to the newly created activity upon creation and removed as properties from the submitted object.

        {
          "@context": "http://www.w3.org/ns/activitystreams",
          "type": "Note",
          "content": "This is a note",
          "to": ["https://example.org/~john/"],
          "cc": ["http://example.com/~erik/followers"]
        }
        
The above example could be converted to this:
        {
          "@context": "http://www.w3.org/ns/activitystreams",
          "type": "Activity"
          "actor": "https://example.net/~mallory",
          "object": {
            "id": "https://example.com/~alice/note/72",
            "type": "Note",
            "author": "https://example.net/~mallory",
            "content": "This is a note",
            "published": "2015-02-10T15:04:55Z"
          },
          "published": "2015-02-10T15:04:55Z",
          "to": ["https://example.org/~john/"],
          "cc": ["http://example.com/~erik/followers"]
        }
        

Update Activity

The Update activity is used when updating an already existing object. The object should be modified to reflect the new structure in defined in the update activity.

Delete Activity

The Delete activity is used to delete an already existing object. This MUST leave a shell of the object that will be displayed in activities which reference the deleted object. If the deleted object is requested the server should respond with the HTTP 410 Gone status code.

A deleted object:

            {
              "@context": "http://www.w3.org/ns/activitystreams",
              "id": "https://example.com/~alice/note/72",
              "type": "Note",
              "published": "2015-02-10T15:04:55Z",
              "updated": "2015-02-10T15:04:55Z",
              "deleted": "2015-02-10T15:04:55Z",
            }
          

Follow Activity

The Follow activity is used to subscribe to the activities of another user. Once the user has followed a user, activities shared with the Follows of that user SHOULD be added to the actors's inbox.

Add Activity

The Add activity is used to add the object to the collection specified in the target property of the activity.

Remove Activity

The Remove activity is used to remove the object from the collection specified in the target property of the activity.

Block Activity

The Block activity is used to indicate that the actor does not want a user (defined in the object property) to be able to interact with objects posted by the user. The server SHOULD prevent the user from interacting with any object posted by the actor.

Undo Activity

The Undo activity is used to undo a previous activity. For example, Undo may be used to undo a previous Like or Follow. The undo activity and the activity being undone MUST both have the same author. Side effects (such as adding activities to a user's inbox after a Follow) should be undone, to the extent possible.

There are some exceptions where there is an existing and explicit "inverse activity" which should be used instead. Create based activities should instead use Delete, and Add activities should use Remove.

Change Log

Changes from 28 January 2016 WD to this version

  • Various typo fixes.
  • Moved following, followers, url to "SHOULD" properties.
  • Removed objectTypes text and simplified "streams" definition.
  • Removed vague term "share activity".
  • Changed MAY to MUST for inbox reading.
  • Replaced all "@type" and "@id" with "type" and "id".
  • Clarified and fixed up followers section.
  • Added "Note" type to receiving activity example.
  • Dropped implied "@context" from an example.
  • Added audience targeting to examples.
  • Make inReplyTo more explicit.
  • New text allowing silent and private activities.
  • Removed reference to access control in Delivery section.
  • Added section clarifying the ACL.
  • Added an optional "streams" property example.
  • Moved preferredUsername, summary, icon to "MAY" provideable actor properties.
  • Clarified dereferencing collection to deliver to contained users.
  • Require validating objects posted to inbox.
  • Incoming activities MUST have a valid URI as id.
  • Clarify when identifiers are required.
  • Permit submitting objects without activities for client to server object creation.