Microsub-spec

From IndieWeb
Revision as of 01:33, 10 April 2017 by Aaronparecki.com (talk | contribs) (first draft of Microsub)
(diff) โ† Older revision | Latest revision (diff) | Newer revision โ†’ (diff)

The Microsub spec provides a standardized way for clients to consume and interact with feeds collected by a server.

The Microsub server is responsible for managing the accounts you follow, retrieving updates from them, and the Microsub endpoint provides the feed entries in a normalized format for easy consumption by clients.

Endpoints

The Microsub endpoint is where the client will make all API requests. All API requests require authentication with a Bearer access token that the client needs to obtain. If the client does not have a preexisting relationship with the server, then the following method of discovery and authorization should be used to obtain an access token and discover the Microsub endpoint.

It is possible for a client to be pre-configured with a Microsub endpoint, or to use other methods of obtaining an access token if there is a preexisting relationship between the client and the server providing the Microsub endpoint.

Discovery

The client first performs discovery on the user's profile URL to find the Microsub endpoint and authorization endpoint. Given a user's profile URL, perform an HTTP GET request and look for either a <link rel="microsub"> or HTTP Link header with a rel value of microsub. Additionally, look for links with rel values authorization_endpoint and token_endpoint.

Link: <https://aaronpk.example/auth>; rel="authorization_endpoint"
Link: <https://aaronpk.example/token>; rel="token"
Link: <https://aaronpk.example/microsub>; rel="microsub"
<link rel="authorization_endpoint" href="https://aaronpk.example/auth">
<link rel="token" href="https://aaronpk.example/token">
<link rel="microsub" href="https://aaronpk.example/microsub">

The Microsub endpoint URL MUST NOT contain a fragment, and MAY contain query string components. If the URL contains a query string, then any GET requests MUST properly append the additional parameters to the query string, and POST requests MUST NOT send the query string properties in the post body. e.g. making a GET request with the additional query string component "action=config" to the endpoint "/endpoints?type=microsub" would result in a URL of "/endpoints?type=microsub&action=config"

(Note: The client will likely want to also find the Micropub endpoint for the user so that the client can post replies and other interactions to the user's website.)

Authentication and Authorization

The client builds an IndieAuth authorization request URL at the authorization endpoint, and directs the user's browser there. In a native client, the client should use a system-native browser, rather than using a web view embedded in the application. See [OAuth 2.0 for Native Apps](https://tools.ietf.org/html/draft-ietf-oauth-native-apps) for more details.

Build a URL with the following query parameters:

  • me={the user's profile URL} - the URL that the user entered at which the Microsub endpoint was found
  • response_type=code
  • client_id={the client's URL, e.g. its home page}
  • state={random state} - the client should generate a unique state value, and verify that it matches when the user is redirected
  • redirect_uri={the client's redirect URI} - for native apps, this may include a custom URL scheme
  • scope={requested scope} - a space-separated list of scopes that the client is requesting

Scopes

Microsub defines the following scopes:

  • read - this is the minimum scope clients should request. this allows clients to have read access to channels.
  • follow - allows the client to manage the following list
  • mute - allows the client to mute and unmute users
  • block - allows the client to block and unblock users
  • channels - allows the client to create and edit channels

Additionally, the client may request Micropub scopes, in order for the user to be able to reply or like posts from within the client.

  • create
  • update
  • delete

The recommended set of scopes to request is read follow mute block create, which enables a rich set of interaction on the client, while also protecting the security of the user by default.

The user will visit the authorization endpoint, and if they approve the request, their browser will be redirected back to the client's redirect URI with a code and state in the URL.

HTTP/1.1 302 Found
Location: https://client.example/redirect?code=xxxxxxxx
                                         &state=1234567890

The client verifies the state value matches the state it generated for the initial request, and can then exchange the authorization code for an access token.

The client makes a POST request to the token endpoint initially discovered, with the following parameters:

  • grant_type=authorization_code
  • code=xxxxxxxxx
  • redirect_uri={the client's redirect URI}
  • client_id={the client's URL}

The response will be a JSON object with the following keys:

{
  "access_token": "XXXXXXXXXXX",
  "scope": "read follow mute block create",
  "me": "https://aaronpk.example/"
}

The me value returned MAY be different from the original me value input, but MUST have a matching host name. This enables support for multi-user websites, and allows the user's server to normalize profile URLs, e.g. it will always return https://aaronpk.example/ even if the user initially enters http://aaronpk.example.

The scopes returned MAY be different from what the client requested, based on whether the user choose to deny certain scopes, or grant additional scopes during the authorization request.

Configuration

The client will need to request some basic configuration information in order to set up the interface. To make a configuration request, make a GET request to the endpoint with a query string parameter q=config. The following properties will be returned in the response.

GET /microsub?q=config
Authorization: Bearer xxxxxxxxx

HTTP/1.1 200 Ok
Content-type: application/json

{
  "channels": [
    {
      "uid": "indieweb",
      "name": "IndieWeb"
    },
    {
      "uid": "w3c",
      "name": "W3C"
    },
  ]
}
  • channels - an array of channels configured for the user. A channel is described by three properties.
    • uid - a string representation of a user-specific unique ID for the channel. This uid will be unique for each user, but may be duplicated across different users. Some implementations will use constant strings such as "example", while others may use database IDs such as "15029932", or a URL such as "http://user.example.com/channel/foo". The valid characters for a uid are any URL-safe character.
    • name - the display name for the channel. This may include any valid UTF-8 sequence. The client should use this name when displaying the name of the channel in the interface.

Channels

In addition to any channels listed in the configuration response, all Microsub servers have two channels with the uid default and notifications. Clients should display these with the localized names "Home" and "Notifications". Some users may not have any additional channels.

Some actions may want to apply to every channel, so the uid of global is reserved for this purpose. Actions such as mute that want to mute a user across every channel should use the channel uid of global.

Users

All users are identified by profile URLs, with some constraints. User profile URLs MUST use either the http or https scheme, and MAY contain path and query string components, and MUST NOT contain fragments.

Actions

All operations in Microsub are considered "actions", and are specified with a query string or form body parameter of action.

  • channels
  • timeline
  • follow / unfollow
  • mute / unmute
  • block / unblock
  • preview

Actions that operate within the context of a channel can accept a query string or form body parameter of channel specifying the uid of the channel to use. If no channel is specified, then the default channel is assumed.

Timelines

action=timeline

GET

Retrieve the entries in a given channel.

The response SHOULD include HTTP Link headers with rel values of next and prev that will return future and past entries from the channel, which the client will use for paging.

The response will include a property items with an array of post objects. See below for documentation on posts.

``` {

 "items": [
   { ... },
   { ... }
 ]

} ```

Following

action=follow

GET

Retrieve the list of feeds being followed in the given channel.

TODO: document the response format

POST

Follow a new URL in a channel.

POST /microsub
Content-type: application/x-www-form-urlencoded

action=follow&channel=indieweb&url=http://tantek.com/

When a request to the follow endpoint is made, the Microsub server registers the follow action, and begins delivering content at that URL into the channel. The Microsub server can subscribe to the target URL via any mechanism available, but most often will attempt a WebSub subscription for its HTML+Microformats, or Atom/RSS feed, and fall back to polling if that fails.

New entries at the followed URL will appear in the channel when fetched from the channel's timeline.

TODO: document the response format

Muting

action=mute

Muting users will cause all posts by the muted user to be hidden from display. The server MAY still store the posts internally, so that un-muting the user will cause past entries to appear again.

Any side effect at the server SHOULD NOT cause the muted user to know they have been muted. Muting users SHOULD NOT have any externally visible side effects.

For example, in the context of the [Salmention](https://indieweb.org/Salmention) spec, the server should still behave as if the muted user was not muted.

GET

Retrieve the list of users that are muted in the given channel.

Request

GET /microsub?action=mute HTTP/1.1

Response

HTTP/1.1 200 Ok
Content-type: application/json

{
  "items": [
    {
      "type": "card",
      "url": "http://annoying.example.com/",
      "name": "Annoying Person",
      "photo": "http://annoying.example.com/photo.jpg"
    },
    {
      ...
    }
  ]
}

POST

Mute a user in a channel, or with the uid global mutes the user across every channel.

Request

POST /microsub HTTP/1.1
Content-type: application/x-www-form-urlencoded

action=mute&url=https://annoying.example.com/

Response

HTTP/1.1 200 Ok

Unmute

POST

To unmute a user, use action=unmute and provide the URL of the account to unmute. Unmuting an account that was previously not muted has no effect and should not be considered an error.

Blocking

action=block

Blocking users will cause all previous posts by the blocked user to be hidden or deleted, and future posts by that user should not be stored. Additionally, the server SHOULD NOT produce any content or side effect that would notify the blocked user about a post. It is acceptable for the blocked user to know they have been blocked.

For example, in the context of the Webmention spec, the server should not send webmentions even if the user mentions the blocked user in a post. In the context of the Salmention spec, the server should stop sending follow-up webmentions to the blocked user.

GET

Retrieve the list of users that are blocked in the given channel.

TODO: document the response format

POST

Block a user in a channel, or with the uid global blocks the user across every channel.

Preview

action=preview

The "preview" action exists so that the client can display a preview of a URL to the user before the user wants to create a subscription for it. The preview should show as much about the URL as the server can determine, such as basic profile information about the user, and a few recent entries by the user. There should be no permanent side effects created by previewing a URL, and as much as possible, the URL being previewed should not be provided with identifying information of the user who is previewing the URL.

TODO: document the response format

Channels

action=channels

Post

create a new channel

TODO: document request and response

Types of Feeds

The specific types and formats of feeds that can be followed is out of scope of Microsub. Instead, it's up to the Microsub server to support whichever feed formats it wishes. Typically, Microsub servers will prefer a Microformats 2 feed such as an h-feed or list of h-entrys, and will then fall back to finding an Atom or RSS feed. Other types of feeds may be supported, but clients should not make any assumptions about which formats are supported, and should make use of the "preview" action so that users have an indication of whether a subscription will succeed.

Objects

Posts

Posts are the basic object used in the API. Posts can be short status updates, photos, videos, podcast episodes, checkins, and many other content types. Post objects returned in the "items" array MUST be valid jf2 post objects.