ActivityPub

W3C 권고안

이 버전:
https://www.w3.org/TR/2018/REC-activitypub-20180123/
최신 발행 버전:
https://www.w3.org/TR/activitypub/
최신 편집본:
https://w3c.github.io/activitypub/
테스트 스위트:
https://test.activitypub.rocks/
구현 보고서:
https://activitypub.rocks/implementation-report
이전 버전:
https://www.w3.org/TR/2017/PR-activitypub-20171205/
에디터:
Christine Lemmer-Webber
Jessica Tallon
저자:
Christine Lemmer-Webber
Jessica Tallon
Erin Shepherd
Amy Guy
Evan Prodromou
저장소:
Git 저장소
이슈
커밋

발행 후 보고된 오류나 이슈는 정오표를 꼭 확인해 주세요.

또한 번역본도 참고하세요.


초록

ActivityPub 프로토콜은 [ActivityStreams] 2.0 데이터 포맷을 기반으로 한 분산형 소셜 네트워킹 프로토콜입니다. 이 프로토콜은 클라이언트에서 서버로의 API를 통해 콘텐츠를 생성, 수정, 삭제할 수 있으며, 알림 및 콘텐츠 전달을 위한 연합 서버 간 API도 제공합니다.

이 문서의 상태

이 섹션은 이 문서가 발행될 당시의 상태를 설명합니다. 다른 문서가 이 문서를 대체할 수 있습니다. 현재 W3C 발행물 목록 및 이 기술 보고서의 최신 개정판은 W3C 기술 보고서 인덱스 https://www.w3.org/TR/에서 확인할 수 있습니다.

이 문서는 소셜 웹 워킹 그룹에 의해 권고안으로 발행되었습니다.

모든 관심 있는 분들은 워킹 그룹의 이슈 트래커를 통해 구현 및 버그 제보와 의견을 남길 수 있습니다. 해당 내용은 소셜 웹 커뮤니티 그룹에서 논의되고, 차후 본 사양의 개선에 반영될 수 있습니다.

워킹 그룹의 구현 보고서를 참조하세요.

이 문서는 W3C 회원, 소프트웨어 개발자, 기타 W3C 그룹 및 관심자들의 검토를 받았으며, W3C 이사의 승인을 얻어 W3C 권고안으로 채택되었습니다. 이 문서는 안정적인 문서이며, 참고 자료나 다른 문서에서 인용하여 사용할 수 있습니다. W3C의 권고안 마련 목적은 이 사양의 주목도를 높이고 광범위한 배포를 촉진하는 것입니다. 이는 웹의 기능성과 상호운용성을 강화합니다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에서 작성되었습니다. W3C는 본 그룹의 산출물과 관련한 공개 특허 공개 목록을 관리합니다. 해당 페이지에는 특허 공개 방법에 대한 안내도 포함되어 있습니다. 당사자가 실제로 특허를 알고 있고, 그 특허가 본질적 권리청구(Essential Claim(s))를 포함한다고 생각한다면, W3C 특허 정책 제 6조에 따라 공개해야 합니다.

이 문서는 2017년 3월 1일 W3C 프로세스 문서의 관리를 받습니다.

1. 개요

ActivityPub은 두 계층을 제공합니다:

ActivityPub 구현체는 이 중 하나만 구현할 수도 있고, 둘 다 구현할 수도 있습니다. 하지만 둘 중 하나를 구현했다면, 다른 하나도 구현하는 것이 많은 단계를 추가하지 않고도 가능하고, 둘 다 구현하면 (귀하의 웹사이트가 분산형 소셜 웹의 일부가 되고, 다양한 소셜 웹사이트에서 동작하는 클라이언트와 클라이언트 라이브러리를 활용할 수 있어) 많은 이점이 있습니다.

ActivityPub에서 사용자는 서버의 계정을 통해 "액터"로 표현됩니다. 사용자의 여러 서버 계정은 각각 다른 액터에 대응합니다. 모든 액터는 다음을 가집니다:

액터의 인박스와 아웃박스

이들은 엔드포인트, 즉 ActivityPub 액터의 ActivityStreams 설명에 나열된 URL들입니다. (ActivityStreams에 대해선 뒤에서 다룹니다.)

친구 Alyssa P. Hacker의 레코드 예시는 다음과 같습니다:

예시 1
{"@context": "https://www.w3.org/ns/activitystreams",
 "type": "Person",
 "id": "https://social.example/alyssa/",
 "name": "Alyssa P. Hacker",
 "preferredUsername": "alyssa",
 "summary": "MIT 출신, Lisp 애호가",
 "inbox": "https://social.example/alyssa/inbox/",
 "outbox": "https://social.example/alyssa/outbox/",
 "followers": "https://social.example/alyssa/followers/",
 "following": "https://social.example/alyssa/following/",
 "liked": "https://social.example/alyssa/liked/"}

ActivityPub은 단어집으로 [ActivityStreams]를 사용합니다. ActivityStreams는 소셜 네트워크 내 활동과 콘텐츠를 표현하는 데 필요한 공통 용어들을 모두 제공하므로 아주 유용합니다. 대부분의 경우 ActivityStreams에 필요한 모든 단어가 이미 들어 있지만, 만약 부족하다면 [JSON-LD]를 통해 ActivityStreams를 확장할 수도 있습니다. JSON-LD가 무엇인지 안다면, 그에 따른 연결 데이터 방법들의 장점도 이용할 수 있습니다. 만약 모른다 해도, JSON-LD 문서와 ActivityStreams는 일반적인 간단한 JSON처럼 이해할 수 있습니다. (확장을 추가할 때 JSON-LD의 진가가 드러납니다.)

좋아요. Alyssa는 친구들과 대화하고 싶어 하고, 친구들도 그녀와 대화하고 싶어 할 것입니다! "inbox"와 "outbox"가 이런 부분을 도와줍니다. GET과 POST 방식에 따라 동작이 다릅니다. 어떻게 동작하는지 살펴봅시다:

inbox와 outbox로 들어오고 나가는 메시지 흐름

네, 요약하자면:

물론, 마지막 방법(타인의 outbox에서 GET)만으로 모든 메시지를 받게 하면 연합 프로토콜로서 매우 비효율적일 것입니다! 실제 연합은 보통 서버가 액터의 메시지를 다른 서버의 액터의 inbox로 POST함으로써 일어납니다.

예시를 살펴봅시다! Alyssa가 친구 Ben Bitdiddle과 연락하려 합니다. 최근 Ben에게 책을 빌려줬고, 돌려받고 싶은 것입니다. Alyssa가 작성한 ActivityStreams 메시지는 다음과 같습니다:

예시 2
{"@context": "https://www.w3.org/ns/activitystreams",
 "type": "Note",
 "to": ["https://chatty.example/ben/"],
 "attributedTo": "https://social.example/alyssa/",
 "content": "혹시, 내가 빌려준 책 다 읽었니?"}

이 노트는 Ben에게 전달됩니다. Alyssa는 이를 자신의 outbox에 POST합니다.

액터가 메시지를 outbox에 게시하는 그림

이 메시지는 액티비티가 아닌 객체이기 때문에, 서버는 새 객체 생성임을 인식하고 이를 Create 액티비티로 감쌉니다. (ActivityPub의 액티비티는 일반적으로 액터가 어떤 객체에 행위를 하는 패턴을 따릅니다. 여기서 행위는 Person이 Note 객체를 Create하는 것입니다.)

예시 3
{"@context": "https://www.w3.org/ns/activitystreams",
 "type": "Create",
 "id": "https://social.example/alyssa/posts/a29a6843-9feb-4c74-a7f7-081b9c9201d3",
 "to": ["https://chatty.example/ben/"],
 "actor": "https://social.example/alyssa/",
 "object": {"type": "Note",
            "id": "https://social.example/alyssa/posts/49e2d03d-b53a-4c4c-a95c-94a6abf45a19",
            "attributedTo": "https://social.example/alyssa/",
            "to": ["https://chatty.example/ben/"],
            "content": "혹시, 내가 빌려준 책 다 읽었니?"}}

Alyssa의 서버는 Ben의 ActivityStreams 액터 객체를 찾아 그에 해당하는 inbox 엔드포인트를 찾아 객체를 Ben의 inbox로 POST합니다.

서버가 원격 액터의 inbox로 게시하는 그림

엄밀히 따지면 이는 두 단계로 나뉩니다... 하나는 클라이언트-서버 통신, 하나는 서버-서버 통신(연합)을 위한 것입니다. 그러나 이 예시에서는 두 단계를 연속 사용하므로, 아웃박스→인박스로의 메시지 전달을 추상적으로 하나의 흐름으로 볼 수 있습니다:

한 액터의 outbox에서 다른 액터의 inbox로 노트가 전달되는 그림

멋지네요! 시간이 지난 후 Alyssa는 새로운 메시지가 왔는지 확인합니다. 그녀의 휴대폰이 GET으로 inbox를 폴링하고, 친구들이 올린 고양이 동영상과 언니가 올린 조카 사진 속에 다음과 같은 메시지가 보입니다:

예시 4
{"@context": "https://www.w3.org/ns/activitystreams",
 "type": "Create",
 "id": "https://chatty.example/ben/p/51086",
 "to": ["https://social.example/alyssa/"],
 "actor": "https://chatty.example/ben/",
 "object": {"type": "Note",
            "id": "https://chatty.example/ben/p/51085",
            "attributedTo": "https://chatty.example/ben/",
            "to": ["https://social.example/alyssa/"],
            "inReplyTo": "https://social.example/alyssa/posts/49e2d03d-b53a-4c4c-a95c-94a6abf45a19",
            "content": "<p>아, 미안! 내일 꼭 돌려줄게.</p>
                        <p>레지스터 머신 부분 복습 좀 했어, 오랜만이라서.</p>"}}

Alyssa는 안도하며 Ben의 게시물에 '좋아요'를 누릅니다:

예시 5
{"@context": "https://www.w3.org/ns/activitystreams",
 "type": "Like",
 "id": "https://social.example/alyssa/posts/5312e10e-5110-42e5-a09b-934882b3ecec",
 "to": ["https://chatty.example/ben/"],
 "actor": "https://social.example/alyssa/",
 "object": "https://chatty.example/ben/p/51086"}

Alyssa는 이 메시지를 outbox에 POST합니다. (액티비티이므로 서버는 따로 Create 객체로 포장하지 않아도 됨을 인지합니다.)

기분이 좋아진 Alyssa는 팔로워들에게 공개 메시지를 포스팅하기로 합니다. 잠시 후 그녀의 팔로워 컬렉션의 모든 멤버뿐 아니라 "Public" 그룹이 지정되어 있기 때문에 누구나 이 메시지를 읽을 수 있습니다.

예시 6
{"@context": "https://www.w3.org/ns/activitystreams",
 "type": "Create",
 "id": "https://social.example/alyssa/posts/9282e9cc-14d0-42b3-a758-d6aeca6c876b",
 "to": ["https://social.example/alyssa/followers/",
        "https://www.w3.org/ns/activitystreams#Public"],
 "actor": "https://social.example/alyssa/",
 "object": {"type": "Note",
            "id": "https://social.example/alyssa/posts/d18c55d4-8a63-4181-9745-4e6cf7938fa1",
            "attributedTo": "https://social.example/alyssa/",
            "to": ["https://social.example/alyssa/followers/",
                   "https://www.w3.org/ns/activitystreams#Public"],
            "content": "친구에게 책을 빌려주는 건 기쁨, 다시 돌려받는 건 더 큰 기쁨! :)"}}

1.1 소셜 웹 워킹 그룹

ActivityPub은 소셜 웹 워킹 그룹에서 제작 중인 여러 관련 명세 중 하나입니다. 다른 방법이나 보완 프로토콜에 관심 있는 구현자는 [Micropub] 및 개요 문서 [Social-Web-Protocols]를 참고하세요.

2. 적합성

비규범적(non-normative)으로 표시된 섹션 외에도, 이 명세서의 모든 작성 지침, 다이어그램, 예시, 주석은 비규범적입니다. 이외 모든 내용은 규범적(normative)입니다.

키워드 MAY, MUST, MUST NOT, SHOULD, SHOULD NOT는 [RFC2119]에 명시된 대로 해석해야 합니다.

2.1 사양 프로필

이 명세서는 긴밀하게 연관되고 상호작용하는 두 개의 프로토콜을 정의합니다:

클라이언트-서버 프로토콜 또는 "Social API"
이 프로토콜은 클라이언트가 사용자 대신 동작할 수 있도록 허용합니다. 예를 들어, 이 프로토콜은 모바일 앱이 사용자의 액터 소셜 스트림과 상호작용하는 데 사용됩니다.
서버-서버 프로토콜 또는 "연합 프로토콜"
이 프로토콜은 서로 다른 서버의 액터 간에 활동을 배포하여 동일한 소셜 그래프에 묶을 수 있도록 사용됩니다.

ActivityPub 명세는 이 두 프로토콜 중 하나라도 구현하면 다른 하나를 지원하는 데 추가 비용이 거의 없도록 설계됐습니다. 그러나 서버는 여전히 둘 중 하나만 구현할 수도 있습니다. 이로 인해 아래 세 가지 적합성 클래스가 생깁니다:

ActivityPub 적합 클라이언트
이는 클라이언트-서버 프로토콜의 클라이언트 부분 전체를 구현한 케이스에 적용됩니다.
ActivityPub 적합 서버
이는 클라이언트-서버 프로토콜의 서버 부분 전체를 구현한 케이스에 적용됩니다.
ActivityPub 적합 연합 서버
이는 연합 프로토콜 전체를 구현한 케이스에 해당합니다.

명세의 특정 부분이 연합 프로토콜 구현에만 적용될 때는 이를 명확히 표시합니다. 또한, 어떤 요구사항이 명시될 때는 그것이 클라이언트(클라이언트-서버 프로토콜), 서버(클라이언트-서버 프로토콜), 혹은 서버-서버 프로토콜의 송신/수신 서버에 적용되는지 분명히 나타냅니다.

3. 객체(Objects)

객체는 [ActivityStreams]와 ActivityPub 모두의 핵심 개념입니다. 객체는 종종 액티비티로 감싸여 컬렉션 스트림에 포함되며, 컬렉션 또한 객체의 하위 클래스입니다. [Activity-Vocabulary] 문서의 Core Classes 를 특히 참고하세요. ActivityPub은 이 단어집의 맵핑을 매우 정확히 따릅니다.

ActivityPub은 ActivityStreams가 제공하는 용어 외에 몇 가지 용어를 추가로 정의합니다. 이 용어들은 ActivityPub JSON-LD context (https://www.w3.org/ns/activitystreams)에 제공됩니다. 구현자는 객체 정의에 ActivityPub context를 권장적으로 포함해야 하며, 필요하다면 선택적으로 추가 컨텍스트도 넣을 수 있습니다.

ActivityPub은 ActivityStreams와 동일한 URI / IRI 규칙을 따릅니다.

서버는 권장적으로 수신한 콘텐츠를 검증하여 콘텐츠 위조 공격을 막아야 합니다. (최소한 원본에서 받은 객체가 동일하게 나타나는지 확인해야 하며, 가능하다면 서명 검증 등 추가 검증 기법을 적용하는 것이 좋습니다.) 이 문서는 특정 검증 메커니즘을 권위 있게 명시하지 않지만, 보안 고려사항에서 제안 및 좋은 관행을 참고하세요.

예를 들어, example.com이 아래 액티비티를 받았다면:
예시 7
{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Like",
  "actor": "https://example.net/~mallory",
  "to": ["https://hatchat.example/sarah/",
         "https://example.com/peeps/john/"],
  "object": {
    "@context": {"@language": "en"},
    "id": "https://example.org/~alice/note/23",
    "type": "Note",
    "attributedTo": "https://example.org/~alice",
    "content": "I'm a goat"
  }
}
서버는 id의 경로를 실제로 dereference(확인)해서 존재하는 객체인지, 유효한 객체인지, 위조되지 않았는지 확인해야 합니다. (이 예시에서, Mallory가 Alice가 쓴 것처럼 위장할 수 있기 때문입니다.)

3.1 객체 식별자(Object Identifiers)

[ActivityStreams]의 모든 객체는 전역적으로 고유한 식별자를 가져야 합니다. ActivityPub에서는 이 요구를 확장하여, ActivityPub 프로토콜을 통해 배포되는 모든 객체는 반드시 고유한 전역 식별자를 가져야 하며, 의도적으로 일시적인 객체(예: 조회 불가능한 단명 채팅 메시지나 게임 알림 등)가 아니라면 반드시 필요한 조건입니다. 이런 식별자는 아래 둘 중 하나여야 합니다:

  1. 출처 서버 권한(authority)을 갖는 HTTPS URI 등 공개 dereferencing이 가능한 URI. (공개 콘텐츠는 권장적으로 HTTPS URI 사용)
  2. JSON null 객체로 명시적으로 지정된 ID. 이는 익명 객체(상위 컨텍스트의 일부임을 의미).

서버-서버 통신으로 게시되는 액티비티에는, 그 활동이 명시적으로 일시적이 아닌 한 반드시 식별자를 제공해야 합니다. 하지만 클라이언트-서버 통신의 경우, outbox로 게시된 객체에 id가 지정되지 않았을 때 서버는 해당 액터의 네임스페이스에 객체 ID를 할당해 게시 객체에 붙여줘야 합니다(권장).

모든 객체에는 다음 속성이 있습니다:

id
객체의 전역 고유 식별자(객체가 일시적이면 id생략 가능).
type
객체의 타입.

3.2 객체 검색

HTTP GET 메소드는 객체의 id 속성에 대해 dereference될 수 있으며, 이를 통해 액티비티를 조회할 수 있습니다. 서버는 [RFC7231]에 정의된 HTTP 콘텐츠 협상을 선택적으로 사용할 수 있지만, application/ld+json; profile="https://www.w3.org/ns/activitystreams" 미디어 타입으로 요청받을 경우 반드시 ActivityStreams 객체 표현(리턴값)을 제공해야 하고, 또한 가능하다면 application/activity+json에도 ActivityStreams 표현을 제공해야 합니다. 클라이언트는 액티비티를 조회하려면 Accept 헤더를 application/ld+json; profile="https://www.w3.org/ns/activitystreams" 미디어 타입으로 반드시 지정해야 합니다.

서버는 위 요구를 충족하지 않는 요청에 대해 다른 동작을 구현할 수 있습니다. (예: 추가적인 기존 프로토콜 지원, 하나의 URI로 HTML과 ActivityStreams 포맷 모두 제공 등)

서버는 B.1 인증 및 권한 부여에서 규정한 대로 권한 인증을 요구할 수 있으며, 추가적인 권한 정책을 자체적으로 둘 수도 있습니다. 서버는 권한 검증에 실패한 요청을 적절한 HTTP 오류 코드나, 객체 존재 자체를 비공개로 하고 싶으면 403 Forbidden 오류 코드로 실패 처리해야 합니다. 비공개 객체 존재 유무 자체도 노출하고 싶지 않으면, 원 서버는 404 Not Found 상태코드로 응답할 수도 있습니다.

3.3 source 속성

[Activity-Vocabulary]가 정의한 모든 속성 외에도, ActivityPub은 Objectsource 속성을 추가로 제공합니다. source 속성은 content 마크업이 어디서 파생되었는지, 즉 원본 정보나 향후 클라이언트 수정 시 활용할 수 있도록 표시합니다. 일반적으로 source에서 content로의 변환은 클라이언트가 담당하며(그 반대는 아님), source의 형식을 직접 지원할 수 있는지는 클라이언트에 따라 다릅니다.

source 값은 contentmediaType 필드를 갖는 별도의 객체로, 원본 정보를 담습니다.

예시 8
{
  "@context": ["https://www.w3.org/ns/activitystreams",
               {"@language": "en"}],
  "type": "Note",
  "id": "http://postparty.example/p/2415",
  "content": "<p>나는 <em>딸기를</em> 정말 좋아한다!</p>",
  "source": {
    "content": "나는 *정말* 딸기를 좋아한다!",
    "mediaType": "text/markdown"}
}
참고: 클라이언트가 mediaType을 의미 있게 처리하지 못할 때 어떻게 해야 할까요?

일반적으로, 사용자가 글을 쓸 때 썼던 원본(source) 포맷 그대로 다시 수정할 수 있게 하는 것이 최선입니다. 하지만 각 클라이언트가 모든 원본 타입을 좋은 인터페이스로 제공할 수 있는 것은 아닙니다. 클라이언트는 대체로 source에서 content로 변환만 할 뿐, 역방향은 잘 못 합니다. 어떤 클라이언트가 content 마크업을 에디터에 보여주고 source는 무시할 수도 있는데, 이 경우 다음번 수정 시 원본 source를 잃게 됩니다. 이런 동작을 할 땐 최소한 "원본 포맷을 이해하지 못해 무시하니 편집 시 기존 원본이 사라질 수 있음"이라는 경고는 꼭 부드럽게 표시해야 합니다.

예를 들어, Alyssa P. Hacker는 Org mode(Org mode)를 활용해 ActivityPub 블로그 글을 Emacs 클라이언트로 씁니다. 나중엔 휴대폰 클라이언트로 글을 수정하려는데, 이 앱은 text/x-org가 뭔지 모르고 HTML로 변환도 못 하니, content만 빈 텍스트박스에 띄워줍니다. 편집란 위에는 "이 글은 우리가 지원하지 않는 마크업 언어로 작성되었습니다. 수정하면 원본을 잃게 됩니다."라는 경고가 뜹니다. Alyssa는 작은 오타 정도는 원본 org-mode 마크업을 잃으면서 수정할 가치가 없다고 판단해, 집에 가서 나중에 수정하기로 합니다.

4. 액터(Actors)

ActivityPub의 액터는 일반적으로 ActivityStreams 액터 유형 중 하나이지만, 반드시 그럴 필요는 없습니다. 예를 들어, Profile 객체를 액터로 사용할 수도 있고, ActivityStreams 확장 타입일 수도 있습니다. 액터는 ActivityPub에서 다른 오브젝트처럼 조회됩니다. 다른 ActivityStreams 객체와 마찬가지로 액터도 id를 가지며, 이 값은 URI입니다. 만약 사용자 인터페이스(로그인 폼 등)에 바로 입력되는 경우에는 이름을 좀 더 간단히 입력할 수 있도록 지원하는 것이 좋습니다. 이를 위해, 다음과 같이 ID 정규화가 권장됩니다:

  1. 입력된 ID가 유효한 URI라면 그대로 사용합니다.
  2. 사용자가 입력한 값이, URI의 스킴(예: example.org/alice/)을 빠뜨린 것으로 보이는 경우, 클라이언트는 선택적으로 기본 스킴(가능하면 https)을 자동으로 붙여줄 수 있습니다.
  3. 그 외의 경우라면, 입력값은 유효하지 않다고 간주해야 합니다.

액터의 URI를 식별하면, dereference(실제 조회)해야 합니다.

참고
ActivityPub은 "user"와 Actor의 관계를 특정 방식으로 지정하지 않으며, 다양한 구성이 가능합니다. 여러 명의 사용자 또는 조직이 하나의 액터를 관리할 수도 있고, 마찬가지로 한 명의 사용자나 한 조직이 여러 액터를 관리할 수도 있습니다. 반대로, 액터는 봇이나 자동화 프로세스같은 소프트웨어를 나타낼 수도 있습니다. 더 상세한 "user" 모델링, 예를 들어 동일 사용자가 관리하는 여러 액터를 연결한다거나, 하나의 액터를 여러 프로필/측면으로 보여주는 것 등은 구현에 따라 다르게 할 수 있습니다.

4.1 액터 객체

액터 객체는 3.1 Object 식별자에서 요구하는 속성 이외에, 아래 속성들을 반드시 포함해야 합니다:

inbox
이 액터가 받은 모든 메시지들이 포함된 [ActivityStreams] OrderedCollection에 대한 참조입니다. 자세한 내용은 5.2 Inbox를 참조하세요.
outbox
이 액터가 생성한 모든 메시지들이 포함된 [ActivityStreams] OrderedCollection입니다. 5.1 Outbox를 참고하세요.

구현에서는 아래 속성도 권장적으로 제공해야 합니다:

following
이 액터가 팔로우하는 액터들의 [ActivityStreams] 컬렉션 링크입니다. 5.4 Following Collection 참고.
followers
이 액터를 팔로우하는 액터들의 [ActivityStreams] 컬렉션 링크입니다. 5.3 Followers Collection 참고.

구현에서는 아래 속성도 선택적으로 제공할 수 있습니다:

liked
이 액터가 '좋아요' 누른 오브젝트들의 [ActivityStreams] 컬렉션 링크입니다. 5.5 Liked Collection 참고.
예시 9
{
  "@context": ["https://www.w3.org/ns/activitystreams",
               {"@language": "ja"}],
  "type": "Person",
  "id": "https://kenzoishii.example.com/",
  "following": "https://kenzoishii.example.com/following.json",
  "followers": "https://kenzoishii.example.com/followers.json",
  "liked": "https://kenzoishii.example.com/liked.json",
  "inbox": "https://kenzoishii.example.com/inbox.json",
  "outbox": "https://kenzoishii.example.com/feed.json",
  "preferredUsername": "kenzoishii",
  "name": "石井健蔵",
  "summary": "この方はただの例です",
  "icon": [
    "https://kenzoishii.example.com/image/165987aklre4"
  ]
}

구현에서는 아래 속성도 선택적으로 추가할 수 있습니다:

streams
참고로 쓸 수 있는 추가 컬렉션의 목록입니다.
preferredUsername
액터를 지칭할 때 쓸 수 있는 짧은 사용자명(고유성은 보장되지 않음).
endpoints
추가적인(주로 서버/도메인 전체에 해당) 엔드포인트를 매핑한 JSON 오브젝트입니다. 액터 자신이나 이 액터를 참조하는 사람이 활용할 수 있습니다. 이 매핑은 액터 문서 안에 값으로 포함될 수도 있고, 이런 속성을 가진 JSON-LD 문서 링크일 수도 있습니다.

endpoints 매핑에는 아래 속성을 선택적으로 포함할 수 있습니다:

proxyUrl
이 액터의 클라이언트가 인증이 필요한 원격 ActivityStreams 오브젝트에 접근할 수 있도록 하는 엔드포인트 URI. 이 엔드포인트를 사용하려면, 클라이언트는 x-www-form-urlencodedid 파라미터에 요청 오브젝트의 id를 넣어 POST합니다.
oauthAuthorizationEndpoint
만약 OAuth 2.0 베어러 토큰 [RFC6749] [RFC6750]이 클라이언트-서버 상호작용 인증에 사용된다면, 이 엔드포인트는 웹 브라우저 사용자 인증을 통한 새로운 권한 부여 획득용 URI입니다.
oauthTokenEndpoint
만약 OAuth 2.0 베어러 토큰 [RFC6749] [RFC6750]이 클라이언트-서버 상호작용 인증에 사용된다면, 이 엔드포인트는 클라이언트가 엑세스 토큰을 획득하는 URI입니다.
provideClientKey
Linked Data Signatures 및 HTTP Signatures가 인증/권한부여에 사용될 경우, 브라우저 사용자가 클라이언트-서버 상호작용 에 쓰일 클라이언트 공개키를 승인하는 URI입니다.
signClientKey
Linked Data Signatures 및 HTTP Signatures가 인증/권한부여에 사용될 경우, 클라이언트 키를 액터의 키로 일정 시간동안 서명하여 외부 서버에서 액터를 대신해 동작할 수 있도록 하는 URI입니다.
sharedInbox
공개로 주소지정된 활동 및 팔로워에게 보낼 활동을 효율적으로 전달할 때 사용하는 선택적 엔드포인트입니다. 자세한 내용은 Shared Inbox Delivery를 참고하세요. sharedInbox 엔드포인트는 권장적으로 Public 특수 컬렉션에 주소지정된 오브젝트들이 담긴 공개 OrderedCollection 오브젝트여야 합니다. sharedInbox를 읽을 때 절대 Public이 아닌 오브젝트는 표시하지 않아야 합니다.
참고

ActivityPub의 상위 단어집인 [ActivityStreams]의 모든 속성은 ActivityPub 액터에서 사용될 수 있습니다. ActivityStreams 속성 중에는 ActivityPub 구현에서 어떻게 쓰이는지 보여주기 위한 예시가 될 만한 속성들이 있습니다.

url
액터의 "프로필 웹페이지"로 가는 링크(단, id와 다를 때).
name
액터의 선호 "닉네임" 또는 "표시 이름".
summary
사용자가 자기 자신을 간략하게 소개하는 한 줄 요약/자기소개.
icon
프로필 사진을 나타내는 이미지 혹은 Image 오브젝트에 대한 링크(썸네일일 수 있음).
참고

name, preferredUsername, summary 등 자연어 값을 담는 속성들은 ActivityStreams에서 정의된 자연어 지원 규칙을 사용합니다.

5. 컬렉션(Collections)

[ActivityStreams]에서 컬렉션 개념이 정의되고, ActivityPub은 특별 동작이 지정된 여러 컬렉션을 정의합니다. ActivityPub은 ActivityStreams 페이징도 활용해 대량 오브젝트를 순회할 수 있습니다.

이 중 일부 컬렉션은 OrderedCollection임이 명시되고, 나머지는 Collection 혹은 OrderedCollection이 될 수 있습니다. OrderedCollection반드시 항상 역순(최신→과거) 순서로 표시되어야 합니다.

참고

역순 정렬 기준이 무엇인지는 구현에 맡깁니다. 예를 들어 대부분의 SQL 스타일 데이터베이스는 증가하는 정수 ID를 이용해, 삽입 순서를 처리할 수 있습니다. 다른 데이터베이스에서는 삽입 시간을 나타내는 타임스탬프를 더 선호할 수도 있습니다. 어떤 속성이든 상관없으나, 새 항목이 앞에 오도록 순서는 반드시 유지되어야 합니다. 자주 바뀌는 속성(예: "최근 수정시각" 등)을 정렬 기준으로 써서는 안 됩니다.

5.1 Outbox

outbox는 액터의 outbox 프로필 속성에서 찾을 수 있습니다. outbox반드시 OrderedCollection이어야 합니다.

outbox 스트림에는 사용자가 발행한 액티비티가 들어 있는데, 실제로 액티비티를 볼 수 있는지 여부는 요청자의 권한에 따라 달라집니다(즉, 읽는 사람의 권한에 따라 outbox 내용이 필터링됨). 만약 Authorization 없이 요청한다면, 서버는 Public으로 주소지정된 게시물만 응답해야 합니다. 실제로는 서버마다 사용자가 볼 수 있는 아이템 수를 제한하거나 다르게 구현할 수 있습니다.

outbox는 HTTP POST 요청을 받으며, 동작 방식은 클라이언트-서버 상호작용에서 설명합니다.

5.2 Inbox

inbox는 액터의 inbox 프로필 속성에서 찾을 수 있습니다. inbox반드시 OrderedCollection이어야 합니다.

inbox 스트림에는 액터가 받은 모든 액티비티가 들어 있습니다. 서버는 권장적으로 요청자 권한에 따라 내용을 필터링해야 합니다. 일반적으로 inbox 소유자는 자신의 모든 내용을 볼 수 있지만, 접근 제어에 따라 일부는 공개·일부는 권한 인증이 필요할 수 있습니다.

서버는 inbox에 반환하는 액티비티의 중복을 반드시 제거해야 합니다. 예를 들어 액티비티가 한 액터의 팔로워와 특정 팔로워 모두에 보내지는 경우 등, 서버가 반복 수신자 목록을 중복 제거하지 못하면 중복이 발생할 수 있습니다. 이때 id가 같은 액티비티를 걸러내야 합니다.

연합 서버의 액터는 inbox에서 HTTP POST 요청을 받을 수 있으며, 동작 방식은 Delivery에서 설명합니다. 비연합 서버는 권장적으로 POST 요청을 받으면 405(Method Not Allowed)로 응답해야 합니다.

5.3 Followers 컬렉션

모든 액터followers 컬렉션을 권장적으로 가져야 합니다. 이는 액터에 대해 Follow 액티비티를 보낸, 즉 팔로우한 주체의 목록으로, 부수 효과로 추가된 항목입니다. 해당 액터를 팔로우하는 모든 액터의 목록을 여기에 찾을 수 있습니다. followers 컬렉션은 반드시 OrderedCollection 또는 Collection 여야 하며, 로그인된 사용자의 권한에 따라, 혹은 인증이 없는 경우 적절하게 필터링 가능합니다.

참고: 기본 알림 전달 대상

팔로우 액티비티는 일반적으로 액터가 생성한 오브젝트를 볼 수 있도록 요청하는 것입니다. 따라서 Followers 컬렉션은 알림의 기본 전달 대상로 적합합니다.

5.4 Following 컬렉션

모든 액터는 following 컬렉션을 권장적으로 가져야 합니다. 이는 액터가 팔로우한 모든 대상의 목록으로, 부수 효과로 추가된 항목입니다. following 컬렉션은 반드시 OrderedCollection 또는 Collection 여야 하며, 로그인된 사용자의 권한에 따라, 혹은 인증이 없는 경우 적절하게 필터링 가능합니다.

5.5 Liked 컬렉션

모든 액터는 liked 컬렉션을 선택적으로 가질 수 있습니다. 이는 액터의 모든 Like 액티비티가 부수 효과로 추가되어 모인 목록입니다. liked 컬렉션은 반드시 OrderedCollection 또는 Collection 여야 하며, 로그인된 사용자의 권한에 따라, 혹은 인증이 없는 경우 적절하게 필터링 가능합니다.

5.6 공개 주소지정(Public Addressing)

[ActivityStreams] 컬렉션 및 오브젝트 외에도, Activity는 특별한 "public" 컬렉션(https://www.w3.org/ns/activitystreams#Public)에 주소지정할 수도 있습니다. 예시:

예시 10
{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "https://www.w3.org/ns/activitystreams#Public",
  "type": "Collection"
}

이 특별 URI로 주소지정된 Activity는 누구나 인증 없이 접근할 수 있어야 합니다. 구현에서는 "public" 특수 컬렉션으로의 전달을 절대 허용하면 안 됩니다. 해당 컬렉션은 실제 activity를 받는 것이 불가능합니다. 다만, 액터는 sharedInbox 엔드포인트를 두고 공개 글(혹은 팔로워 전용 글)의 효율적 일괄 배포에 이용할 수 있습니다. 자세한 내용은 7.1.3 Shared Inbox Delivery 참고.

참고

ActivityStreams 오브젝트를 ActivityStreams JSON-LD 컨텍스트로 compact(압축)하면, https://www.w3.org/ns/activitystreams#PublicPublic 또는 as:Public로 변환될 수 있습니다. 이는 Public 컬렉션의 유효한 표현입니다. ActivityStreams 오브젝트를 단순 JSON으로 처리하고 JSON-LD 툴링 없이 Activity를 로컬 컨텍스트로 변환하지 않는 구현도 이 부분을 인지하고 세 가지 표현 모두 허용해야 합니다.

5.7 Likes 컬렉션

모든 오브젝트는 likes 컬렉션을 선택적으로 가질 수 있습니다. 이는 이 오브젝트가 object 속성에 명시된 모든 Like 액티비티 목록으로, 부수 효과로 추가됩니다. likes 컬렉션은 반드시 OrderedCollection 또는 Collection 여야 하며, 로그인된 사용자의 권한에 따라, 혹은 인증이 없는 경우 적절하게 필터링 가능합니다.

참고

likes 컬렉션과 비슷하지만 다른 liked 컬렉션을 혼동하지 말아야 합니다. 요약하자면:

  • liked: 액터 객체에만 존재하는 속성. 이는 해당 액터가 "좋아요"를 누른 Like 액티비티들의 컬렉션으로, outbox 전달의 부수 효과로 추가됩니다.
  • likes: 모든 오브젝트에 존재할 수 있는 속성. 이는 이 오브젝트를 참조하는 Like 액티비티의 컬렉션으로, inbox 전달의 부수 효과로 추가됩니다.

5.8 Shares 컬렉션

모든 오브젝트는 shares 컬렉션을 선택적으로 가질 수 있습니다. 이는 이 오브젝트를 object 속성으로 한 Announce 액티비티들의 목록이며, 부수 효과로 추가됩니다. shares 컬렉션은 반드시 OrderedCollection 또는 Collection 여야 하며, 로그인된 사용자의 권한에 따라, 혹은 인증이 없는 경우 적절하게 필터링 가능합니다.

6. 클라이언트-서버 상호작용

[ActivityStreams]에 의해 정의된 Activity는 소셜 그래프 내에서 콘텐츠를 생성, 수정, 공유하는 핵심 메커니즘입니다.

클라이언트-서버 상호작용은 클라이언트가 액터의 outbox에 Activity를 포스팅함으로써 이루어집니다. 이를 위해, 클라이언트는 프로필에서 액터의 outbox URL을 반드시 발견해야 하며, 그 후 해당 URL에 application/ld+json; profile="https://www.w3.org/ns/activitystreams" 타입의 HTTP POST 요청을 반드시 보내야 합니다. 서버는 application/activity+json의 Content-Type 또는 Accept 헤더를 클라이언트-서버 상호작용에서 application/ld+json; profile="https://www.w3.org/ns/activitystreams"와 동등하게 해석할 수 있습니다. 요청은 outbox의 소유자인 사용자의 자격 증명으로 반드시 인증되어야 합니다. POST 요청의 본문에는 하나의 Activity(내부에 오브젝트가 포함될 수도 있음) 또는 서버가 Create activity로 감쌀 수 있는 단일 비-Activity 오브젝트필수로 들어가야 합니다.

예시 11: Activity를 Outbox에 제출
POST /outbox/ HTTP/1.1
Host: dustycloud.org
Authorization: Bearer XXXXXXXXXXX
Content-Type: application/ld+json; profile="https://www.w3.org/ns/activitystreams"

{
  "@context": ["https://www.w3.org/ns/activitystreams",
               {"@language": "en"}],
  "type": "Like",
  "actor": "https://dustycloud.org/chris/",
  "name": "Chris liked 'Minimal ActivityPub update client'",
  "object": "https://rhiaro.co.uk/2016/05/minimal-activitypub",
  "to": ["https://rhiaro.co.uk/#amy",
         "https://dustycloud.org/followers",
         "https://rhiaro.co.uk/followers/"],
  "cc": "https://e14n.com/evan"
}

Activity의 id 속성에 값이 포함되어 제출될 경우, 서버는 이를 무시하고 새 id새로 생성해야 합니다. 서버는 반드시 201 Created HTTP 코드를 반환하고, Activity가 일시적(transient)이 아닌 경우 반드시idLocation 헤더에 포함시켜야 합니다.

예시 12: 제출된 Activity에 대한 Outbox 응답
HTTP/1.1 201 Created
Location: https://dustycloud.org/likes/345

서버는 반드시 ActivityStreams 오브젝트에서 btobcc 속성이 있으면 이를 전달 전 제거해야 하며, 단, delivery에서 수신자를 결정할 때는 bto / bcc에 원래 저장된 주소 정보를 반드시 사용해야 합니다.

서버는 그런 다음 생성된 Activity를 outbox 컬렉션에 반드시 추가해야 합니다. Activity의 종류에 따라 서버는 추가적인 부수 효과를 실행해야 할 수 있습니다. (단, Activity가 outbox에 언제 표시되는지는 보장되지 않으며 지연 후 나타나거나 삭제될 수도 있습니다.) 각 Activity별 부수 효과는 아래에 설명되어 있습니다.

클라이언트-서버 지원을 구현하지 않은 서버에 오브젝트를 제출하는 시도는 405 Method Not Allowed 응답을 권장적으로 반환해야 합니다.

HTTP 캐싱 메커니즘 [RFC7234]은 적절한 경우 서버-클라이언트 양방향에서 최대한 준수해야 합니다.

6.1 클라이언트 주소지정

클라이언트는 새 Activity에 대해 올바르게 주소지정할 책임이 있습니다. 이는 실제 클라이언트 구현에 어느 정도 의존하지만, 클라이언트는 서버가 to, bto, cc, bcc, audience 필드에 있는 수신자에게만 Activity를 전달함을 인지해야 합니다.

Followers 컬렉션과/또는 Public 컬렉션은 새 Activity의 기본 주소지정 대상으로 적합한 선택입니다.

클라이언트는 새 Activity에 object, target, inReplyTo 및/또는 tag 필드를 통해 첨부된 오브젝트를 검사하고, 그 오브젝트의 actor 또는 attributedTo 속성(들)을 추출해야 하며, 선택적으로 주소지정 속성들도 가져와서, 새 Activity의 tocc에도 추가할 수 있습니다. 클라이언트는 첨부 오브젝트를 재귀적으로 따라가도 되지만, 이런 경우 권장적으로 제한을 두어야 합니다. (참고: 이는 클라이언트가 주소지정되는 액터의 컬렉션 전체를 개별 수신자로 '펼치라'는 의미가 아님)

클라이언트는 이 주소지정 값을 UI에서 사용자가 수정할 기회를 제공해도 됩니다.

예를 들어 Chris가 Amy의 아래 게시글(article)에 좋아요를 누르는 경우:

예시 13: Article
{
  "@context": ["https://www.w3.org/ns/activitystreams",
               {"@language": "en-GB"}],
  "id": "https://rhiaro.co.uk/2016/05/minimal-activitypub",
  "type": "Article",
  "name": "Minimal ActivityPub update client",
  "content": "Today I finished morph, a client for posting ActivityStreams2...",
  "attributedTo": "https://rhiaro.co.uk/#amy",
  "to": "https://rhiaro.co.uk/followers/",
  "cc": "https://e14n.com/evan"
}

클라이언트는 아래와 같이 like를 생성합니다:

예시 14: 게시글에 대한 Like
{
  "@context": ["https://www.w3.org/ns/activitystreams",
               {"@language": "en"}],
  "type": "Like",
  "actor": "https://dustycloud.org/chris/",
  "summary": "Chris liked 'Minimal ActivityPub update client'",
  "object": "https://rhiaro.co.uk/2016/05/minimal-activitypub",
  "to": ["https://rhiaro.co.uk/#amy",
         "https://dustycloud.org/followers",
         "https://rhiaro.co.uk/followers/"],
  "cc": "https://e14n.com/evan"
}

받는 쪽 outbox는 delivery를 통해 Chris(좋아요 누른 사람)의 팔로워뿐 아니라, Amy와 Amy의 팔로워(Evan 포함)까지 알림을 보냅니다.

다음과 같은 Activity를 outbox에 제출하는 클라이언트는 object 속성을 반드시 Activity에 제공해야 합니다: Create, Update, Delete, Follow, Add, Remove, Like, Block, Undo. 또한 다음 Activity를 outbox에 제출할 때는 target 속성도 반드시 제공해야 합니다: Add, Remove.

6.2 Create Activity

Create Activity는 새 오브젝트 게시에 사용됩니다. Activity 내부(object 속성)에 포함된 오브젝트가 생성된다는 부수 효과가 있습니다.

Create Activity가 게시될 때, 해당 Activity의 actor를 오브젝트의 attributedTo 필드에 반드시 복사해야 합니다.

Create Activity와 그 object의 주소지정이 다르면 혼란이 발생할 수 있으므로, 서버는 초기 배포 시 Create Activity의 수신자를 object에도 복사하고 반대도 권장적으로 복사해야 합니다. 단, 이후 object의 주소지정은 Create의 주소지정을 변경하지 않고 별도로 바뀔 수도 있습니다(예: Update activity로).

6.2.1 Create Activity 없이 오브젝트 생성

클라이언트-서버 포스팅에서는, Activity로 감싸지 않은 오브젝트를 직접 제출하여 생성하는 것도 가능합니다. 서버는 Activity 서브타입이 아닌 유효한 [ActivityStreams] 오브젝트를 outbox에 반드시 수락해야 합니다. 이후 서버는 이 오브젝트를 Create Activityobject반드시 감싸야 합니다. 일시적이지 않은(normal) 오브젝트의 경우 서버는 wrapping된 Create와 내부 Object 양쪽 모두에 id반드시 부여해야 합니다.

참고

서버가 반환하는 Location 값은 오브젝트가 아닌 새 Create activity의 URL이어야 합니다.

오브젝트에 있는 to, bto, cc, bcc, audience 속성은 모두 반드시 서버가 새 Create Activity로 복사해야 합니다.

예시 15: Audience를 지정한 오브젝트
{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Note",
  "content": "This is a note",
  "published": "2015-02-10T15:04:55Z",
  "to": ["https://example.org/~john/"],
  "cc": ["https://example.com/~erik/followers",
         "https://www.w3.org/ns/activitystreams#Public"]
}
위 예시는 다음처럼 변환될 수 있습니다:
예시 16: 서버에서 생성된 Create Activity wrapper
{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Create",
  "id": "https://example.net/~mallory/87374",
  "actor": "https://example.net/~mallory",
  "object": {
    "id": "https://example.com/~mallory/note/72",
    "type": "Note",
    "attributedTo": "https://example.net/~mallory",
    "content": "This is a note",
    "published": "2015-02-10T15:04:55Z",
    "to": ["https://example.org/~john/"],
    "cc": ["https://example.com/~erik/followers",
           "https://www.w3.org/ns/activitystreams#Public"]
  },
  "published": "2015-02-10T15:04:55Z",
  "to": ["https://example.org/~john/"],
  "cc": ["https://example.com/~erik/followers",
         "https://www.w3.org/ns/activitystreams#Public"]
}

6.3 Update Activity

Update Activity는 기존 오브젝트를 수정할 때 사용됩니다. 이 Activity의 부수 효과로, 액터가 해당 오브젝트에 대한 수정 권한이 있는 경우 object가 Activity에서 정의한 새 구조로 반드시 변경됩니다.

6.3.1 부분 업데이트

클라이언트-서버 상호작용에서는 '부분 업데이트'가 지원됩니다. 문서 전체를 한 번에 수정하는 것이 아니라, 전달된 모든 키-값 쌍은 기존 값을 새 값으로 대체합니다. 이는 오브젝트 최상위 필드에만 적용됩니다. 특별 예외로, 값이 json의 null 타입이라면 해당 필드는 서버 오브젝트 표현에서 삭제되어야 합니다.

이 동작은 클라이언트가 서버에 POST하는 클라이언트-서버 상호작용에만 해당됩니다. 서버-서버 또는 서버→클라이언트 업데이트는 부분 업데이트가 적용된 이후의 전체 오브젝트 표현이 전달되어야 합니다. 자세한 내용은 서버-서버 상호작용을 위한 Update activity를 참고하세요.

6.4 Delete Activity

Delete Activity는 기존 오브젝트를 삭제할 때 사용됩니다. 이 Activity의 부수 효과로, 서버는 objectTombstone 타입으로 대체해 삭제된 오브젝트를 참조하는 Activity에 표시될 수 있도록 동작할 수 있습니다. 삭제된 오브젝트 요청 시 서버는 Tombstone을 본문으로 반환한다면 410 Gone 상태코드로 답해야 하며, 그렇지 않으면 404 Not Found로 답해야 합니다.

삭제된 오브젝트 예시:

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

6.5 Follow Activity

Follow Activity는 다른 액터의 활동을 구독하는 데 사용됩니다.

outbox에서 이 Activity를 수신할 경우, 서버는 이후 Accept Activity가 이 Follow Activity를 object로 포함해 도착할 때에만, objectactorfollowing 컬렉션추가해야 합니다.

6.6 Add Activity

outboxAdd Activity를 수신 시, 서버는 target 속성의 컬렉션에 object추가해야 합니다. 단,

6.7 Remove Activity

outboxRemove activity를 수신 시, 서버는 target의 컬렉션에서 object제거해야 합니다. 단,

6.8 Like Activity

Like Activity는 actorobject를 좋아함을 나타냅니다.

outbox에서 이 Activity를 수신 시, 서버는 objectactorliked 컬렉션추가해야 합니다.

6.9 Block Activity

Block Activity는 게시 액터가 object 속성에 지정된 액터가 자신이 게시한 오브젝트와 상호작용하지 못하도록 하고 싶을 때 사용됩니다. 서버는 차단된 사용자가 액터가 게시한 오브젝트와 상호작용하지 못하도록 막아야 합니다.

서버는 Block Activity를 object에게 전달하면 안 됩니다.

6.10 Undo Activity

Undo Activity는 이전 Activity를 취소할 때 사용됩니다. 자세한 내용은 Activity Vocabulary 문서의 역활동 및 "Undo" 항목을 참고하십시오. 예를 들어, Undo는 이전의 Like, Follow, Block을 되돌릴 때 활용할 수 있습니다. undo 및 대상이 되는 활동은 반드시 같은 actor를 가져야 하며, 가능한 한 모든 부수 효과도 취소되어야 합니다. (예: Like를 undo하면 이전에 올린 카운터도 적절히 감소해야 함)

단, 명시적인 역활동(inverse activity)이 따로 존재하는 경우에는 그것을 사용해야 합니다. Create 기반 액티비티는 Delete로, AddRemove로 undo해야 합니다.

6.11 전달

연합 서버는 outbox에 게시된 모든 Activity에 대해 outbox 전달반드시 수행해야 합니다.

6.12 미디어 업로드

이 섹션은 비규범적입니다.

서버는 이미지, 비디오 등 바이너리 데이터를 Activity에 참조될 수 있도록 사용하는 문서 업로드를 지원할 수 있지만, 자세한 메커니즘은 이번 ActivityPub 버전의 범위에 포함되어 있지 않습니다. 소셜웹 커뮤니티 그룹에서 이에 대한 상세 프로토콜을 ActivityPub Media Upload 보고서에서 논의 중입니다.

7. 서버-서버 상호작용

서버는 다른 서버와 통신하고 소셜 그래프 전반에 정보를 전파하기 위해 액터의 inbox 엔드포인트에 activity를 게시합니다. 네트워크를 통해 전송되는 Activity는 가능하면 id를 포함해야 하며, 일시적인 용도라면 생략해도 됩니다.

POST 요청(예: inbox로)은 반드시 Content-Type을 application/ld+json; profile="https://www.w3.org/ns/activitystreams"으로, GET 요청은(참고 3.2 객체 검색) Accept 헤더를 application/ld+json; profile="https://www.w3.org/ns/activitystreams"로 보내야 합니다. 서버는 권장적으로, 서버-서버 상호작용에서 application/activity+json의 Content-Type 또는 Accept 헤더를 application/ld+json; profile="https://www.w3.org/ns/activitystreams"와 동등하게 해석할 수 있습니다.

소셜 그래프 전체로 업데이트를 전파하기 위해, Activity는 적절한 수신자에게 전달되어야 합니다. 수신자는 오브젝트들 간의 링크를 따라 액터에 도달할 때까지 추적하여 결정되고, 그 후 Activity는 해당 액터의 inbox에 삽입됩니다 (전달). 이를 통해 수신 서버는 다음의 작업을 할 수 있습니다:

전달 동작은 예를 들어 다음 경우에 트리거됩니다:

다른 서버의 액터 inbox 또는 sharedInbox 속성에 Activity를 전달하는 서버는 아래 각 Activity별로 object 속성을 반드시 제공해야 합니다: Create, Update, Delete, Follow, Add, Remove, Like, Block, Undo. 또한 아래 Activity에 대해서는 target 속성도 반드시 제공해야 합니다: Add, Remove.

HTTP 캐싱 메커니즘 [RFC7234]은 적절한 경우 다른 서버로부터 응답을 받을 때뿐만 아니라, 응답을 보낼 때도 양쪽에서 권장적으로 준수해야 합니다.

7.1 전달

아래 내용은 오직 연합(federated) 서버 간 통신에 필수입니다.

Activity는 우선 타겟(즉, 액터)의 inbox를 찾고 그 inbox에 Activity를 POST하여 전달됩니다. 전달 대상은 ActivityStreams audience targeting의 규정에 따라, Activity의 to, bto, cc, bcc, audience 필드를 확인해 결정합니다.

inbox는 먼저 대상 액터의 JSON-LD 표현을 조회한 뒤, inbox 속성을 찾아 결정합니다. 수신자가 Collection 또는 OrderedCollection이라면, 서버는 반드시(사용자 인증 정보로) 컬렉션을 dereference해서, 컬렉션 내 각 항목의 inbox를 알아내야 합니다. 서버는 반드시 컬렉션을 통한 연쇄 dereference의 깊이에 제한을 두어야 하며, 보통 1단계만 허용할 수 있습니다.

서버는 최종 타겟 수신자 목록을 반드시 deduplicate(중복 제거)해야 합니다. 또한 Activity의 actor와 동일한 액터는 목록에서 반드시 제외합니다. 즉, 액터 본인이 본인의 Activity를 스스로 수신해서는 안 됩니다.

참고: Silent 및 프라이빗 Activity

수신자가 명시되지 않은 경우의 처리는 정해져 있지 않지만, 명시 안 하면 해당 오브젝트가 완전히 비공개로 남고 접근 통제가 오브젝트 접근을 제한하는 것이 바람직합니다. 만약 단순히 "public" 컬렉션에만 전송하면, 어떤 액터에도 전달되지 않고 해당 액터의 outbox에서만 공개적으로 조회될 수 있습니다.

이후 inbox에(Submit 한 사용자 권한으로) HTTP POST 요청을 하며, 요청 본문에 Activity를 담습니다. Activity는 수신자의 inbox OrderedCollectionitem으로 추가됩니다. 비연합 서버의 inbox로 전달을 시도한 경우 권장적으로 405 Method Not Allowed 응답을 받아야 합니다.

제3의 서버로 전달하는 연합 서버의 경우, 전달은 비동기로 수행해야 하며, 네트워크 오류로 인해 실패한다면 재시도 또한 수행해야 합니다.

참고: 동일 오리진 내 액터 간 Activity 유통에는 내부 메커니즘을 사용할 수 있으며 반드시 HTTP를 쓸 필요는 없습니다.

참고: Linked Data Notifications와의 관계

본 명세를 이해하기 위해 필수로 읽을 필요는 없으나, ActivityPub의 타겟팅 및 전달 메커니즘은 Linked Data Notifications 명세와 상당 부분 겹치며, 양쪽을 함께 결합해서 동작시킬 수도 있음을 기억할 만 합니다. 특히 inbox 속성 자체는 ActivityPub과 Linked Data Notifications 모두 동일하며, 본 문서의 타겟팅 및 전달 시스템도 Linked Data Notifications에서 지원됩니다. ActivityStreams 문서를 JSON-LD compacted 형태뿐만 아니라, Linked Data Notifications는 여러 RDF 시리얼라이제이션도 지원하지만, 이는 ActivityPub 구현에 필수는 아닙니다. 단, LDN 구현과 더 광범위한 호환성을 원한다면 다른 RDF 표현도 지원할 수 있습니다.

7.1.1 서버-서버 outbox 전달 요건

outbox에 오브젝트가 수신될 때 (서버가 클라이언트-서버 상호작용서버-서버 상호작용을 모두 지원하는 경우), 서버는 아래 값이 개인 또는 액터 소유 컬렉션이면, 해당 필드로 전달 해야 합니다:

  • to, bto, cc, bcc, audience

이 값들은 outbox에 Activity를 게시한 클라이언트가 적절히 지정합니다.

7.1.2 Inbox에서 전달(Forwarding)

참고: 고스트 리플라이 문제 방지용 전달

다음 섹션은 연합 네트워크에서 간혹 문제가 되는 "고스트 리플라이" 문제를 완화하기 위한 것입니다. 아래 예시에서 그 문제를 쉽게 볼 수 있습니다.

Alyssa가 학회 발표 성공 소식을 팔로워에게 알리면 Ben도 그 팔로워 목록에 있습니다. Ben은 Alyssa의 메시지에 축하 답글을 달고 본문에 그녀의 팔로워 컬렉션을 수신자로 포함합니다. 하지만 Ben은 Alyssa의 팔로워 컬렉션 멤버를 볼 권한이 없으니, Ben의 서버가 자신의 메시지를 그들의 inbox로 전달하지 못합니다. 이 전달 메커니즘이 없으면 Alyssa가 Ben에게 답장하면, Alyssa의 팔로워들은 Ben의 메시지를 받아본 적 없이 그의 이름이 언급된 답글만 보게 되고, 이는 혼란스럽게 됩니다.

Activity가 inbox에 수신될 때, 원본 서버가 전달하지 못한 수신자에게 다시 메시지를 포워딩해야 합니다. 이를 위해 서버는 아래 조건이 모두 true일 때만 to, cc, audience 필드로 전달해야 합니다:

  • 이 서버가 해당 Activity를 처음 수신하는 경우
  • to, cc, audience 값 중 서버 소유 컬렉션이 포함된 경우
  • inReplyTo, object, target 및/또는 tag 값 중 서버가 소유한 오브젝트가 있는 경우. 서버는 가능하다면 이 값들을 재귀적으로 따라가며 서버가 소유한 연결 오브젝트를 탐색해야 하며, 재귀 깊이에 제한을 두어야 합니다. 단, 포워드할 때는 오리지널 오브젝트의 to, cc, audience만 참조하고, 재귀로 추가 탐색 중 새 수신자는 추가하지 않습니다(클라이언트에 의해 수신자가 변경/제한되었을 수 있으므로).

구현에 따라(예: 스팸 필터링 등) 전달 대상을 서버 임의 기준으로 필터할 수 있습니다.

7.1.3 Shared Inbox 전달

여러 액터를 호스팅하는 서버에서는 모든 팔로워에게 일일이 전달하면 메시지가 너무 많아질 수 있습니다. 또 어떤 서버는 전체 네트워크에 공개 포스트의 목록도 보여주길 원합니다. ActivityPub은 이 두 요구를 위해 선택적 메커니즘을 제공합니다.

오브젝트를 자신의 팔로워에게 전달할 때, 서버는 동일한 sharedInbox를 공유하는 팔로워들을 찾아 따로따로 개별 전달하지 않고 해당 sharedInbox일괄 전달할 수 있습니다. 이렇게 하면 원격/수신 서버가 별도로 타겟팅이나 실제 inbox 전달을 결정하게 됩니다.

또한 오브젝트가 Public 특수 컬렉션에 주소지정될 때는, 서버가 네트워크 내 모든 sharedInbox 엔드포인트로 전달할 수 있습니다.

공개로 주소지정된 Activity를 sharedInbox로 보내는 오리진 서버는 그래도 개별적으로 sharedInbox가 없는 액터나 컬렉션에는 to, bto, cc, bcc, audience를 따로 전달해야 합니다.

7.2 Create Activity

inboxCreate Activity를 수신해도 추가 부수 효과는 거의 없습니다; Activity는 액터의 inbox에 표시되고, 서버는 이 Activity와 딸린 오브젝트의 내부 표현을 저장할 수 있습니다. 그러나 이는 원래 inbox로 전달되는 activity 처리 과정에서 항상 발생하는 현상입니다.

7.3 Update Activity

서버-서버 상호작용에서, Update Activity는 수신 서버가 동일 id를 가진 자체 object의 사본을 Activity에 첨부된 사본으로 업데이트해야 함을 뜻합니다. 클라이언트-서버 Update activity 처리와 달리, 전체 오브젝트를 완전히 덮어쓰는 전체 갱신 방식입니다.

수신 서버는 반드시 Update가 해당 object를 변경할 권한이 있는지 확인해야 합니다. 최소한, Update와 그 object가 같은 오리진인지를 점검해야 합니다.

7.4 Delete Activity

이를 inbox로 수신하면(단, object가 송신 액터/서버 소유라는 전제 하에) 수신 서버는 동일 idobject 내부 표현을 삭제 (및 Tombstone 오브젝트로 대체)해야 합니다.

(참고로, 오리진 서버에서 원격 서버로 activity를 전달한 뒤에는, ActivityPub 프로토콜에 원격 서버 오브젝트 표현의 삭제를 강제할 수 있는 장치는 없습니다.)

7.5 Follow Activity

이를 inbox로 수신하면, 서버는 권장적으로 Followobject로 가진 Accept 또는 Reject activity를 생성해 해당 Follow의 actor에게 전달해야 합니다. Accept 또는 Reject자동으로 생성할 수도 있고, 사용자 입력(예: 검토 후 응답 등) 결과로 생성할 수도 있습니다. 서버가 Reject를 명시적으로 보내지 않도록 할 수도 있지만, 이 경우 요청을 보낸 쪽 서버가 중간 상태에 남을 수 있음을 인지해야 합니다. 예를 들어, 사용자의 프라이버시 보호 위해 Reject를 보내지 않을 수도 있습니다.

Accept가 도착하고 그 object가 이전에 수신자가 보낸 Follow Activity일 경우, 서버는 권장적으로 actor를 수신자의 Followers Collection에 추가해야 합니다. Reject의 경우, 서버는 절대 actor를 수신자의 Followers Collection에 추가하면 안 됩니다.

참고

때때로 Follow 구독이 성공했어도, 나중에 배달이 장기간 실패할 수 있습니다. 네트워크 내 액터가 계속 접근 가능할 것이라는 보장은 없으므로, 구현에서는 이런 상황을 반드시 고려해야 합니다. 예를 들어 팔로워가 6개월 동안 접근 불가 상태면, 배달 서버가 해당 구독자를 followers 목록에서 제거하는 것이 합리적일 수 있습니다. 시간 기준 및 행동 방식은 배달 서버의 재량입니다.

7.6 Accept Activity

이를 inbox에서 수신할 때의 부수 효과는 수신한 object 타입에 따라 다르며, 문서에 정의되지 않은 타입(예: Offer 등)도 수락할 수 있습니다.

inbox로 도착한 Acceptobject가 이전에 수신자가 보낸 Follow activity라면, 서버는 권장적으로 actor를 수신자의 Following Collection에 추가해야 합니다.

7.7 Reject Activity

이를 inbox에서 수신할 때의 부수 효과는 수신한 object 타입에 따라 다르며, 문서에 정의되지 않은 타입(예: Offer 등)도 거절할 수 있습니다.

inbox로 수신된 Rejectobject가 수신자가 이전에 보낸 Follow activity라면, 이는 수신자가 Follow 요청을 승인하지 않았음을 의미합니다. 서버는 절대 actor를 수신자의 Following Collection에 추가하면 안 됩니다.

7.8 Add Activity

inboxAdd Activity를 수신하면, 서버는 target 속성의 컬렉션에 object추가해야 합니다 (단,

7.9 Remove Activity

inboxRemove Activity를 수신하면, 서버는 target 속성의 컬렉션에서 object제거해야 합니다 (단,

7.10 Like Activity

inbox로 이 Activity를 수신하면, 서버는 해당 오브젝트의 like 개수를 증가시키고, 받은 Activity를 likes 컬렉션에(존재한다면) 추가해야 합니다.

7.11 Announce Activity (공유)

inboxAnnounce Activity를 수신하면, 서버는 해당 오브젝트의 공유 개수를 증가시키고, 받은 Activity를 shares 컬렉션에(존재한다면) 추가해야 합니다.

참고
Announce Activity는 타 소셜 네트워크에서 "공유", "리포스트", "부스트"라고 알려진 기능과 동일합니다.

7.12 Undo Activity

Undo Activity는 이전 Activity의 부수 효과를 되돌릴 때 사용합니다. ActivityStreams 문서의 역활동 및 "Undo"를 참고하세요. Undo Activity의 범위와 제한은 클라이언트-서버 상호작용 맥락의 Undo activity와 동일하며, 그 적용 대상이 연합 환경임을 제외하고 동일합니다.

A. 국제화

이 섹션은 비규범적입니다.

연합 네트워크에서는 다양한 국가의 사용자를 확보하는 것이 중요합니다. ActivityStreams는 콘텐츠의 국제화를 위한 도구를 제공합니다. 이는 가능한 한 항상 사용해야 합니다. 그러나 구현체가 사용자가 입력한 콘텐츠에 @language 속성 을 어떻게 지정할지 결정하는 것은 어려울 수 있습니다. W3C 국제화 그룹에서는 언어 감지에 대한 가이드를 제공합니다.

B. 보안 고려사항

이 섹션은 비규범적입니다.

B.1 인증 및 권한 부여

ActivityPub은 인증을 두 가지 목적으로 사용합니다. 첫째로, 클라이언트가 서버에 인증을 제공하기 위함이며, 둘째로, 연합 구조에서 서버가 서로를 인증하기 위함입니다.

표준화 당시에, 인증을 위해 강하게 합의된 메커니즘이 존재하지 않았습니다. 인증의 몇 가지 방향성에 대해서는 Social Web Community Group의 인증 및 권한 부여 모범사례 보고서에서 확인할 수 있습니다.

B.2 검증

서버는 클라이언트가 제출한 콘텐츠를 신뢰해서는 안 되며, 연합 서버 또한 오리진이 아닌 다른 서버로부터 받은 콘텐츠는 어느 정도의 검증 절차 없이는 신뢰하지 않아야 합니다.

서버는 신규 콘텐츠가 실제로 이를 게시한다 주장하는 액터에 의해 작성된 것인지, 그리고 액터가 자신이 변경하려는 리소스를 변경할 권한이 있는지 반드시 확인해야 합니다. 또한 3. 객체(Objects)B.1 인증 및 권한 부여도 참고하세요.

B.3 localhost URI 접근

개발 시에는 localhost에서 동작하는 프로세스를 대상으로 테스트하는 것이 편리한 경우가 많습니다. 하지만 실제 서비스에서 클라이언트나 서버 인스턴스가 localhost로의 요청을 허용하는 것은 위험할 수 있습니다. 인증이 필요 없는 localhost URI로 요청을 보낼 경우, 로컬에서만 접근 가능하다고 가정된 리소스에 의도치 않게 접근하거나 변경될 수 있습니다.

ActivityPub 서버나 클라이언트가 개발 목적으로 localhost URI에 요청을 허용한다면, 반드시 설정 옵션화하여 기본값을 '꺼짐'으로 두는 것이 좋습니다.

B.4 URI 스킴

http, https 외에도 다양한 종류의 URI가 존재합니다. 일부 라이브러리는 여러 URI 스킴의 요청을 똑똑하게 처리하려 하지만, file 등 원치 않는 스킴이 포함되어 있을 수 있습니다. 클라이언트/서버 작성자는 자신의 라이브러리가 어떻게 요청을 처리하는지 꼼꼼히 확인하고, httphttps처럼 안전한 유형만 화이트리스트할 것을 권고합니다.

B.5 재귀 오브젝트

서버는 오브젝트를 재귀적으로 해석할 때 최대 깊이 제한을 두거나, 재귀 참조가 걸린 ActivityStreams 오브젝트를 특별히 처리해야 합니다. 이를 소홀히 하면 서비스 거부(DoS) 취약점이 발생할 수 있습니다.

B.6 스팸(Spam)

네트워크라면 어디든 스팸이 문제이고, 연합 네트워크에서는 특히 더 심각할 수 있습니다. ActivityPub은 스팸 방지를 위한 구체적 메커니즘을 제공하지 않으나, 서버가 신뢰되지 않은 로컬 사용자뿐만 아니라 원격 사용자에 대해서도 스팸 필터 등으로 수신 콘텐츠를 필터링하는 것이 권고됩니다.

B.7 연합 서비스거부(DoS)

서버는 연합 서버로부터의 서비스 거부(DoS) 공격에 대한 방어책을 구현해야 합니다. 예를 들어, 어떤 형태로든 레이트리밋(ratelimiting) 메커니즘을 쓸 수 있습니다. 특히 부수 효과를 수반하는 activity 주변에는 이런 방어책을 특히 강화해야 합니다. 서버는 권장적으로, 예를 들어 지수적 백오프(exponential backoff) 전략을 써서 제출로 인해 다른 서버가 과부하되지 않도록 해야 합니다.

B.8 클라이언트-서버 레이트리밋

서버는 API 클라이언트 제출을 레이트리밋해야 합니다. 그 이유는 두 가지입니다:

  1. 악의적인 클라이언트가 서버에 서비스거부(DoS) 공격을 하는 것을 방지
  2. 서버가 너무 많은 activity를 분배해, 다른 서버의 서비스거부 방어를 유발하지 않도록 보장

B.9 클라이언트-서버 응답 DoS

클라이언트가 너무 큰 컬렉션 때문에 과부하되는 상황을 막기 위해, 서버는 반환하는 컬렉션 페이지의 크기를 제한해야 합니다. 클라이언트도 악의적이거나 손상된 서버에 연결될 경우를 대비해 처리할 최대 응답 크기를 별도로 제한(예: 타임아웃 및 에러 발생)해야 합니다.

B.10 콘텐츠 정제

브라우저 등(또는 기타 리치 텍스트 앱)에 표시되는 activity 필드는, 크로스사이트 스크립팅 공격을 막기 위해 마크업이 포함된 필드를 반드시 정제(sanitize)해야 합니다.

B.11 bto/bcc 속성 표시 금지

btobcc전달 전에 반드시 제거되어야 하며, 서버는 오브젝트를 자체 스토리지 시스템에서 어떻게 표현할지는 자유입니다. 그러나 bto, bcc는 오브젝트/액티비티의 원래 작성자만 알아야 하므로, 화면 표시 시에도 해당 속성은 생략해야 합니다.

C. 감사의 글

이 섹션은 비규범적입니다.

이 명세는 웹에서 연합이라는 분야를 개척해 온 여러 커뮤니티의 오랜 노고와 경험에서 비롯됐습니다. 특히 본 명세의 많은 부분은 OStatus 그리고 Pump API (StatusNet(현 GNU Social) 및 Pump.io가 선구적으로 개발) 의 영향이 큽니다. 이 두 프로젝트 모두 개발자들의 헌신적 노고의 산물이지만, 그 중에서도 Evan Prodromou는 이 분야의 한결같은 리더였으며, 그의 노력이 없었다면 ActivityPub은 지금과 같은 모습으로 존재하지 못했을 것입니다.

Erin Shepherd는 본 명세의 초안을 작성했으며, Pump API 문서의 아이디어에서 출발해 ActivityStreams 1에서 ActivityStreams 2로 바뀐 대목은 거의 모두 새로 썼지만, 주요 개념 상당수는 유지하는 완전 재작성에 가까웠습니다.

표준이 W3C Social Working Group으로 이관된 이후, Jessica Tallon과 Christine Lemmer-Webber가 편집을 맡아 Erin Shepherd의 문서에서 현재 ActivityPub 문서로 전환하는 작업을 주도했습니다. 문서의 많은 부분이 Social Working Group의 오랜 피드백을 거치며 새로 쓰이고 재구성됐습니다.

ActivityPub은 W3C Social Working Group의 많은 멤버들이 꼼꼼하게 남긴 의견을 통해 발전했습니다. 특히 Amy Guy에게 큰 빚을 졌습니다. Amy는 [Social-Web-Protocols] 작업을 통해 여러 Social Working Group 문서 전반의 연결을 누구보다 일목요연하게 정리했고, Christopher Allan Webber와 나흘간의 스프린트로 ActivityPub 명세의 대규모 구조조정의 토대를 닦아주기도 했습니다. 이 개정은 클라이언트-서버/서버 컴포넌트의 구분을 더욱 명확히 하고, ActivityPub 과 [LDN]과의 관계 설명에 명확성을 더하는 등 큰 발전에 기여했습니다. Benjamin Goering이 구현 보고서 템플릿을 만들어 준 데도 특별히 감사드립니다. 명세 전반의 멋진 튜토리얼 일러스트(문서와 동일한 라이선스임)를 제작해 준 mray에게도 감사를 전합니다.

많은 분의 꼼꼼한 리뷰와 피드백도 ActivityPub 발전에 큰 힘이 됐습니다. 특히 다음 분들께 감사드립니다: Aaron Parecki, AJ Jordan, Benjamin Goering, Caleb Langeslag, Elsa Balderrama, elf Pavlik, Eugen Rochko, Erik Wilde, Jason Robinson, Manu Sporny, Michael Vogel, Mike Macgirvin, nightpool, Puck Meerburg, Sandro Hawke, Sarven Capadisli, Tantek Çelik, 그리고 Yuri Volkov.

이 문서는 지구상의 모든 시민에게 바칩니다. 당신은 소통의 자유를 누릴 자격이 있습니다. 우리는 미약하나마 그 권리와 목표에 기여하고자 이 문서를 준비했습니다.

D. 참고 문헌

D.1 규범적 참고문헌

[Activity-Vocabulary]
Activity Vocabulary. J. Snell. ActivityStreams Working Group. Editors Draft. URL: https://www.w3.org/TR/activitystreams-vocabulary/
[ActivityStreams]
Activity Streams 2.0. J. Snell. ActivityStreams Working Group. Editors Draft. URL: https://www.w3.org/TR/activitystreams-core/
[JSON-LD]
JSON-LD 1.0. Manu Sporny; Gregg Kellogg; Markus Lanthaler. W3C. 2014년 1월 16일. W3C 권고안. URL: https://www.w3.org/TR/json-ld/
[LDN]
Linked Data Notifications. Sarven Capadisli; Amy Guy. W3C. 2017년 5월 2일. W3C 권고안. URL: https://www.w3.org/TR/ldn/
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. 1997년 3월. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[RFC7231]
Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content. R. Fielding, Ed.; J. Reschke, Ed.. IETF. 2014년 6월. Proposed Standard. URL: https://tools.ietf.org/html/rfc7231
[RFC7234]
Hypertext Transfer Protocol (HTTP/1.1): Caching. R. Fielding, Ed.; M. Nottingham, Ed.; J. Reschke, Ed.. IETF. 2014년 6월. Proposed Standard. URL: https://tools.ietf.org/html/rfc7234

D.2 참고용 참고문헌

[Micropub]
Micropub. Aaron Parecki. W3C. 2017년 5월 23일. W3C 권고안. URL: https://www.w3.org/TR/micropub/
[RFC6749]
The OAuth 2.0 Authorization Framework. D. Hardt, Ed.. IETF. 2012년 10월. Proposed Standard. URL: https://tools.ietf.org/html/rfc6749
[RFC6750]
The OAuth 2.0 Authorization Framework: Bearer Token Usage. M. Jones; D. Hardt. IETF. 2012년 10월. Proposed Standard. URL: https://tools.ietf.org/html/rfc6750
[Social-Web-Protocols]
Social Web Protocols. Amy Guy. W3C. 2017년 12월 25일. W3C Note. URL: https://www.w3.org/TR/social-web-protocols/