mirror of
https://codeberg.org/fediverse/fep.git
synced 2026-08-08 13:35:51 +00:00
1226 lines
58 KiB
HTML
1226 lines
58 KiB
HTML
|
|
<!doctype html>
|
|
<html lang="en" class="no-js">
|
|
<head>
|
|
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
|
|
<meta name="description" content="Portable ActivityPub objects with server-independent IDs.">
|
|
|
|
|
|
|
|
<link rel="canonical" href="https://helge.codeberg.page/fep/fep/ef61/">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="icon" href="../../assets/logo.png">
|
|
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.7.6">
|
|
|
|
|
|
|
|
<title>FEP-ef61: Portable Objects - Fediverse Enhancement Proposals</title>
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="../../assets/stylesheets/main.484c7ddc.min.css">
|
|
|
|
|
|
<link rel="stylesheet" href="../../assets/stylesheets/palette.ab4e12ef.min.css">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="../../styles/theme.css">
|
|
|
|
<script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
|
|
|
|
|
|
|
|
|
|
|
|
</head>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="indigo">
|
|
|
|
|
|
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
|
|
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
|
|
<label class="md-overlay" for="__drawer"></label>
|
|
<div data-md-component="skip">
|
|
|
|
|
|
<a href="#fep-ef61-portable-objects" class="md-skip">
|
|
Skip to content
|
|
</a>
|
|
|
|
</div>
|
|
<div data-md-component="announce">
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<header class="md-header" data-md-component="header">
|
|
<nav class="md-header__inner md-grid" aria-label="Header">
|
|
<a href="../.." title="Fediverse Enhancement Proposals" class="md-header__button md-logo" aria-label="Fediverse Enhancement Proposals" data-md-component="logo">
|
|
|
|
<img src="../../assets/logo.png" alt="logo">
|
|
|
|
</a>
|
|
<label class="md-header__button md-icon" for="__drawer">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
|
|
</label>
|
|
<div class="md-header__title" data-md-component="header-title">
|
|
<div class="md-header__ellipsis">
|
|
<div class="md-header__topic">
|
|
<span class="md-ellipsis">
|
|
Fediverse Enhancement Proposals
|
|
</span>
|
|
</div>
|
|
<div class="md-header__topic" data-md-component="header-topic">
|
|
<span class="md-ellipsis">
|
|
|
|
FEP-ef61: Portable Objects
|
|
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<form class="md-header__option" data-md-component="palette">
|
|
|
|
|
|
|
|
|
|
<input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="indigo" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_0">
|
|
|
|
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_1" hidden>
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0-4-4m0 10a6 6 0 0 1-6-6 6 6 0 0 1 6-6 6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg>
|
|
</label>
|
|
|
|
|
|
|
|
|
|
|
|
<input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="indigo" data-md-color-accent="indigo" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_1">
|
|
|
|
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_0" hidden>
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 18c-.89 0-1.74-.2-2.5-.55C11.56 16.5 13 14.42 13 12s-1.44-4.5-3.5-5.45C10.26 6.2 11.11 6 12 6a6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg>
|
|
</label>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
|
|
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-header__button md-icon" for="__search">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
|
|
</label>
|
|
<div class="md-search" data-md-component="search" role="dialog">
|
|
<label class="md-search__overlay" for="__search"></label>
|
|
<div class="md-search__inner" role="search">
|
|
<form class="md-search__form" name="search">
|
|
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
|
|
<label class="md-search__icon md-icon" for="__search">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
|
|
</label>
|
|
<nav class="md-search__options" aria-label="Search">
|
|
|
|
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
|
|
</button>
|
|
</nav>
|
|
|
|
</form>
|
|
<div class="md-search__output">
|
|
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
|
|
<div class="md-search-result" data-md-component="search-result">
|
|
<div class="md-search-result__meta">
|
|
Initializing search
|
|
</div>
|
|
<ol class="md-search-result__list" role="presentation"></ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="md-header__source">
|
|
<a href="https://codeberg.org/fediverse/fep" title="Go to repository" class="md-source" data-md-component="source">
|
|
<div class="md-source__icon md-icon">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
|
|
</div>
|
|
<div class="md-source__repository">
|
|
fediverse/fep
|
|
</div>
|
|
</a>
|
|
</div>
|
|
|
|
</nav>
|
|
|
|
</header>
|
|
|
|
<div class="md-container" data-md-component="container">
|
|
|
|
|
|
|
|
|
|
|
|
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
|
|
<div class="md-grid">
|
|
<ul class="md-tabs__list">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-tabs__item">
|
|
<a href="../.." class="md-tabs__link">
|
|
|
|
|
|
|
|
|
|
|
|
Fediverse Enhancement Proposals
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-tabs__item">
|
|
<a href="../../final/" class="md-tabs__link">
|
|
|
|
|
|
|
|
|
|
|
|
Final
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-tabs__item">
|
|
<a href="../../draft/" class="md-tabs__link">
|
|
|
|
|
|
|
|
|
|
|
|
Draft
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-tabs__item">
|
|
<a href="../../withdrawn/" class="md-tabs__link">
|
|
|
|
|
|
|
|
|
|
|
|
Withdrawn
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
|
|
|
|
<main class="md-main" data-md-component="main">
|
|
<div class="md-main__inner md-grid">
|
|
|
|
|
|
|
|
|
|
|
|
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" hidden>
|
|
<div class="md-sidebar__scrollwrap">
|
|
<div class="md-sidebar__inner">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="Navigation" data-md-level="0">
|
|
<label class="md-nav__title" for="__drawer">
|
|
<a href="../.." title="Fediverse Enhancement Proposals" class="md-nav__button md-logo" aria-label="Fediverse Enhancement Proposals" data-md-component="logo">
|
|
|
|
<img src="../../assets/logo.png" alt="logo">
|
|
|
|
</a>
|
|
Fediverse Enhancement Proposals
|
|
</label>
|
|
|
|
<div class="md-nav__source">
|
|
<a href="https://codeberg.org/fediverse/fep" title="Go to repository" class="md-source" data-md-component="source">
|
|
<div class="md-source__icon md-icon">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
|
|
</div>
|
|
<div class="md-source__repository">
|
|
fediverse/fep
|
|
</div>
|
|
</a>
|
|
</div>
|
|
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../.." class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Fediverse Enhancement Proposals
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../final/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Final
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../draft/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Draft
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../withdrawn/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Withdrawn
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
|
|
<div class="md-sidebar__scrollwrap">
|
|
<div class="md-sidebar__inner">
|
|
|
|
|
|
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-nav__title" for="__toc">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
Table of contents
|
|
</label>
|
|
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#summary" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Summary
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#motivation" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Motivation
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#history" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
History
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#requirements" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Requirements
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#identifiers" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Identifiers
|
|
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Identifiers">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#ap-uris" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
'ap' URIs
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comparing-ap-uris" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Comparing 'ap' URIs
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#did-methods" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
DID methods
|
|
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="DID methods">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#didkey" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
did:key
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#portable-objects" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Portable objects
|
|
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Portable objects">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#retrieving-objects" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Retrieving objects
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#authentication-and-authorization" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Authentication and authorization
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#key-management" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Key management
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#portable-actors" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Portable actors
|
|
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Portable actors">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#location-hints" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Location hints
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#inboxes-and-outboxes" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Inboxes and outboxes
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#collections" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Collections
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#media" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Media
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#compatibility" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Compatibility
|
|
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Compatibility">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#identifiers_1" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Identifiers
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#webfinger-addresses" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
WebFinger addresses
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#discussion" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Discussion
|
|
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Discussion">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#discovering-locations" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Discovering locations
|
|
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Discovering locations">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#arbitrary-paths" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Arbitrary paths
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#alternatives-to-gateways-property" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Alternatives to gateways property
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#did-services" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
DID services
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#media-access-control" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Media access control
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#implementations" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Implementations
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#references" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
References
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#copyright" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Copyright
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="md-content" data-md-component="content">
|
|
|
|
<article class="md-content__inner md-typeset">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h1 id="fep-ef61-portable-objects">FEP-ef61: Portable Objects<a class="headerlink" href="#fep-ef61-portable-objects" title="Permanent link">¶</a></h1>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Authors</th>
|
|
<th>Status</th>
|
|
<th>Type</th>
|
|
<th>Date received</th>
|
|
<th>Tracking issue</th>
|
|
<th>Discussions</th>
|
|
<th>Repository</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>silverpill <a href="mailto:@silverpill@mitra.social">@silverpill@mitra.social</a></td>
|
|
<td><code>DRAFT</code></td>
|
|
<td>implementation</td>
|
|
<td>2023-12-06</td>
|
|
<td><a href="https://codeberg.org/fediverse/fep/issues/209">#209</a></td>
|
|
<td><a href="https://codeberg.org/silverpill/feps/issues">Discussions</a></td>
|
|
<td><a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/ef61/fep-ef61.md">codeberg</a></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h2 id="summary">Summary<a class="headerlink" href="#summary" title="Permanent link">¶</a></h2>
|
|
<p>Portable <a href="https://www.w3.org/TR/activitypub/">ActivityPub</a> objects with server-independent IDs.</p>
|
|
<h2 id="motivation">Motivation<a class="headerlink" href="#motivation" title="Permanent link">¶</a></h2>
|
|
<p>Usage of HTTP(S) URIs as identifiers has a major drawback: when the server disappears, everyone who uses it loses their identity and data.</p>
|
|
<p>The proposed solution should satisfy the following constraints:</p>
|
|
<ul>
|
|
<li>User's identity and data should not be tied to a single server.</li>
|
|
<li>Users should have a choice between full control over their identity and data, and delegation of control to a trusted party.</li>
|
|
<li>Implementing the solution in existing software should be as simple as possible. Changes to ActivityPub data model should be kept to a minimum.</li>
|
|
<li>The solution should be compatible with existing and emerging decentralized identity and storage systems.</li>
|
|
<li>The solution should be transport-agnostic.</li>
|
|
</ul>
|
|
<h2 id="history">History<a class="headerlink" href="#history" title="Permanent link">¶</a></h2>
|
|
<p><a href="https://joinfediverse.wiki/index.php?title=Nomadic_identity/en">Nomadic identity</a> mechanism makes identity independent from a server and was originally part of the Zot federation protocol.</p>
|
|
<p><a href="https://codeberg.org/streams/streams">Streams</a> (2021) made nomadic accounts available via the <a href="https://codeberg.org/streams/streams/src/commit/11f5174fdd3dfcd8714974f93d8b8fc50378a193/spec/Nomad/Home.md">Nomad protocol</a>, which supported ActivityStreams serialisation.</p>
|
|
<p><a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/c390/fep-c390.md">FEP-c390</a> (2022) introduced a decentralized identity solution compatible with ActivityPub. It enabled permissionless migration of followers between servers, but didn't provide full data portability.</p>
|
|
<h2 id="requirements">Requirements<a class="headerlink" href="#requirements" title="Permanent link">¶</a></h2>
|
|
<p>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in <a href="https://datatracker.ietf.org/doc/html/rfc2119.html">RFC-2119</a>.</p>
|
|
<h2 id="identifiers">Identifiers<a class="headerlink" href="#identifiers" title="Permanent link">¶</a></h2>
|
|
<p>An <a href="https://www.w3.org/TR/activitypub/">ActivityPub</a> object can be made portable by using an identifier that is not tied to a single server. This proposal describes a new identifier type that has this property and is compatible with the <a href="https://www.w3.org/TR/activitypub/">ActivityPub</a> specification.</p>
|
|
<h3 id="ap-uris">'ap' URIs<a class="headerlink" href="#ap-uris" title="Permanent link">¶</a></h3>
|
|
<p>'ap' URI is constructed according to the <a href="https://datatracker.ietf.org/doc/html/rfc3986.html">RFC-3986</a> specification, but with a <a href="https://www.w3.org/TR/did-core/">Decentralized Identifier</a> in place of the authority:</p>
|
|
<div class="highlight"><pre><span></span><code>ap://did:example:abcdef/path/to/object?name=value#fragment-id
|
|
\_/ \________________/ \____________/ \________/ \_________/
|
|
| | | | |
|
|
scheme authority path query fragment
|
|
</code></pre></div>
|
|
<ul>
|
|
<li>The URI scheme MUST be either <code>ap</code> or <code>ap+ef61</code>. The <code>ap</code> scheme is RECOMMENDED.</li>
|
|
<li>The authority component MUST be a valid <a href="https://www.w3.org/TR/did-core/">DID</a>. Colons and other reserved characters MAY be <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-2.1">percent-encoded</a>.</li>
|
|
<li>The path is REQUIRED. It MUST be treated as an opaque string.</li>
|
|
<li>The query is OPTIONAL. To avoid future conflicts, implementers SHOULD NOT use parameter names that are not defined in this proposal.</li>
|
|
<li>The fragment is OPTIONAL.</li>
|
|
</ul>
|
|
<div class="admonition warning">
|
|
<p class="admonition-title">Warning</p>
|
|
<p>An 'ap' URI is not a valid <a href="https://datatracker.ietf.org/doc/html/rfc3986.html">RFC-3986</a> URI if reserved characters in the authority component are not percent-encoded. Nevertheless, this form is considered canonical.</p>
|
|
</div>
|
|
<div class="admonition warning">
|
|
<p class="admonition-title">Warning</p>
|
|
<p>The recommended URI scheme might be changed to <code>ap+ef61</code> in a future version of this document, because these identifiers are not intended to be used for all ActivityPub objects, but only for portable ones.</p>
|
|
</div>
|
|
<div class="admonition note">
|
|
<p class="admonition-title">Note</p>
|
|
<p>ActivityPub specification <a href="https://www.w3.org/TR/activitypub/#obj-id">requires</a> identifiers to have an authority "belonging to that of their originating server". The authority of 'ap' URI is a DID, which does not belong to any particular server.</p>
|
|
</div>
|
|
<h3 id="comparing-ap-uris">Comparing 'ap' URIs<a class="headerlink" href="#comparing-ap-uris" title="Permanent link">¶</a></h3>
|
|
<p>Two 'ap' URIs are equivalent when their canonical forms are identical.</p>
|
|
<p>To produce a canonical 'ap' URI, the following operations MUST be performed:</p>
|
|
<ul>
|
|
<li>If the URI is a <a href="#compatible-ids">compatible identifier</a>, convert it into an 'ap' URI.</li>
|
|
<li>If the scheme component is <code>ap+ef61</code>, replace it with <code>ap</code>.</li>
|
|
<li>If the authority component is percent-encoded, decode it.</li>
|
|
<li>Remove query component.</li>
|
|
</ul>
|
|
<h3 id="did-methods">DID methods<a class="headerlink" href="#did-methods" title="Permanent link">¶</a></h3>
|
|
<p>Implementers MUST support the <a href="https://w3c-ccg.github.io/did-key-spec/">did:key</a> method. Other DID methods SHOULD NOT be used, as it might hinder interoperability.</p>
|
|
<div class="admonition note">
|
|
<p class="admonition-title">Note</p>
|
|
<p>The following additional DID methods are being considered: <a href="https://w3c-ccg.github.io/did-method-web/">did:web</a>, <a href="https://danubetech.github.io/did-method-dns/">did:dns</a>, <a href="https://identity.foundation/didwebvh/">did:webvh</a> (formerly <code>did:tdw</code>) and <a href="https://arcanican.is/excerpts/did-method-fedi.html">did:fedi</a>.</p>
|
|
</div>
|
|
<p>DID documents SHOULD contain Ed25519 public keys represented as verification methods with <code>Multikey</code> type (as defined in the <a href="https://www.w3.org/TR/cid/#Multikey">Controlled Identifiers</a> specification).</p>
|
|
<p>Any <a href="https://www.w3.org/TR/did-core/#did-url-syntax">DID URL</a> capabilities of a DID method MUST be ignored when working with 'ap' URIs.</p>
|
|
<h4 id="didkey">did:key<a class="headerlink" href="#didkey" title="Permanent link">¶</a></h4>
|
|
<p><code>did:key</code> identifiers MUST be generated using the base58-btc alphabet, even though the specification <a href="https://w3c-ccg.github.io/did-key-spec/#did-key-identifier-syntax">allows both base58-btc and base64url</a>. Using both alphabets in practice could prevent applications from recognizing that two 'ap' URIs with differently encoded authorities refer to the same resource.</p>
|
|
<h2 id="portable-objects">Portable objects<a class="headerlink" href="#portable-objects" title="Permanent link">¶</a></h2>
|
|
<p>Example of a portable object:</p>
|
|
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
|
<span class="w"> </span><span class="nt">"@context"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
|
<span class="w"> </span><span class="s2">"https://www.w3.org/ns/activitystreams"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="s2">"https://w3id.org/security/data-integrity/v1"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="s2">"https://w3id.org/fep/ef61"</span>
|
|
<span class="w"> </span><span class="p">],</span>
|
|
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Note"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ap://did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2/objects/dc505858-08ec-4a80-81dd-e6670fd8c55f"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"attributedTo"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ap://did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2/actor?gateways=https%3A%2F%2Fserver1.example,https%3A%2F%2Fserver2.example"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"inReplyTo"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ap://did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK/objects/f66a006b-fe66-4ca6-9a4c-b292e33712ec"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"content"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Hello!"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"attachment"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
|
<span class="w"> </span><span class="p">{</span>
|
|
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Image"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hl:zQmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"mediaType"</span><span class="p">:</span><span class="w"> </span><span class="s2">"image/png"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"digestMultibase"</span><span class="p">:</span><span class="w"> </span><span class="s2">"zQmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n"</span>
|
|
<span class="w"> </span><span class="p">}</span>
|
|
<span class="w"> </span><span class="p">],</span>
|
|
<span class="w"> </span><span class="nt">"to"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
|
<span class="w"> </span><span class="s2">"ap://did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK/actor"</span>
|
|
<span class="w"> </span><span class="p">],</span>
|
|
<span class="w"> </span><span class="nt">"proof"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
|
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"DataIntegrityProof"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"cryptosuite"</span><span class="p">:</span><span class="w"> </span><span class="s2">"eddsa-jcs-2022"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"created"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2023-02-24T23:36:38Z"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"verificationMethod"</span><span class="p">:</span><span class="w"> </span><span class="s2">"did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2#z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"proofPurpose"</span><span class="p">:</span><span class="w"> </span><span class="s2">"assertionMethod"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"proofValue"</span><span class="p">:</span><span class="w"> </span><span class="s2">"..."</span>
|
|
<span class="w"> </span><span class="p">}</span>
|
|
<span class="p">}</span>
|
|
</code></pre></div>
|
|
<h3 id="retrieving-objects">Retrieving objects<a class="headerlink" href="#retrieving-objects" title="Permanent link">¶</a></h3>
|
|
<p>To dereference an 'ap' URI, the client MUST make HTTP GET request to a gateway endpoint at <a href="https://datatracker.ietf.org/doc/html/rfc8615">well-known</a> location <code>/.well-known/apgateway</code>. The <code>ap://</code> prefix MUST be removed from the URI and the rest of it appended to a gateway URI. The client MUST specify an <code>Accept</code> header with the <code>application/ld+json; profile="https://www.w3.org/ns/activitystreams"</code> media type.</p>
|
|
<p>Example of a request to a gateway:</p>
|
|
<div class="highlight"><pre><span></span><code>GET https://social.example/.well-known/apgateway/did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2/path/to/object
|
|
</code></pre></div>
|
|
<p>ActivityPub objects identified by 'ap' URIs can be stored on multiple servers simultaneously.</p>
|
|
<p>If object identified by 'ap' URI is stored on the server, it MUST return a response with status <code>200 OK</code> containing the requested object. The value of a <code>Content-Type</code> header MUST be <code>application/ld+json; profile="https://www.w3.org/ns/activitystreams"</code>.</p>
|
|
<p>If object identified by 'ap' URI is not stored on the server, it MUST return <code>404 Not Found</code>.</p>
|
|
<p>If an object is not public, the server MUST NOT serve it unless the request is signed by an actor who belongs to object's intended audience.</p>
|
|
<p>When working with portable objects, the server SHOULD treat 'ap' URIs as opaque identifiers (<a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/ae49/fep-ae49.md">semantic routing</a>).</p>
|
|
<div class="admonition note">
|
|
<p class="admonition-title">Note</p>
|
|
<p>This document describes web gateways, which use HTTP transport. However, the data model and authentication mechanism are transport-agnostic and other types of gateways could exist.</p>
|
|
</div>
|
|
<h3 id="authentication-and-authorization">Authentication and authorization<a class="headerlink" href="#authentication-and-authorization" title="Permanent link">¶</a></h3>
|
|
<p>Authentication and authorization are performed in accordance with <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/fe34/fep-fe34.md">FEP-fe34</a> origin-based security model, but with two important differences:</p>
|
|
<ul>
|
|
<li>Cryptographic origins are used. They are similar to web origins described in <a href="https://www.rfc-editor.org/rfc/rfc6454.html">RFC-6454</a> but computed using a different algorithm.</li>
|
|
<li>Authentication via fetching from an origin is not possible. The main authentication method is the verification of an integrity proof.</li>
|
|
</ul>
|
|
<p>The origin of an 'ap' URI is identical to the authority component of its canonical form (i.e. it is a DID without percent encoding).</p>
|
|
<p>The origin of a <a href="https://www.w3.org/TR/did-core/#did-url-syntax">DID URL</a> is identical to its <code>did</code> component.</p>
|
|
<p>Actors, activities and objects identified by 'ap' URIs MUST contain <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/8b32/fep-8b32.md">FEP-8b32</a> integrity proofs. Collections identified by 'ap' URIs MAY contain integrity proofs. If collection doesn't contain an integrity proof, <a href="#collections">another authentication method</a> MUST be used.</p>
|
|
<p>The value of <code>verificationMethod</code> property of the proof MUST be a <a href="https://www.w3.org/TR/did-core/#did-url-syntax">DID URL</a> where the DID matches the authority component of the object's canonical identifier.</p>
|
|
<div class="admonition note">
|
|
<p class="admonition-title">Note</p>
|
|
<p>This document uses terms "actor", "activity", "collection" and "object" according to the classification given in <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/2277/fep-2277.md">FEP-2277</a>.</p>
|
|
</div>
|
|
<h3 id="key-management">Key management<a class="headerlink" href="#key-management" title="Permanent link">¶</a></h3>
|
|
<p>There are different ways to manage secret keys used to secure portable objects:</p>
|
|
<ul>
|
|
<li>Server-side signing: secret keys are managed by a server (gateway). Activities are generated and immediately signed by a server.</li>
|
|
<li>Delegated signing: secret keys are managed by a separate service. Activities are generated by a server, which calls a signing service and then adds integrity proofs to activities.</li>
|
|
<li>Client-side signing: secret keys are managed by a client. Activities are generated and signed by a client, which communicates with a server via <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/ae97/fep-ae97.md">FEP-ae97</a> API.</li>
|
|
</ul>
|
|
<h2 id="portable-actors">Portable actors<a class="headerlink" href="#portable-actors" title="Permanent link">¶</a></h2>
|
|
<p>One <a href="https://www.w3.org/TR/did-1.0/#did-subject">DID subject</a> can control multiple actors (which are differentiated by the path component of an 'ap' URI).</p>
|
|
<p>An actor object identified by 'ap' URI MUST have a <code>gateways</code> property containing an ordered list of gateways where the latest version of that actor object can be retrieved. Each item in the list MUST be an HTTP(S) URI with empty path, query and fragment components. The list MUST contain at least one item.</p>
|
|
<p>Gateways are expected to be the same for all actors under a DID authority and MAY be also specified in the DID document as <a href="https://www.w3.org/TR/did-1.0/#services">services</a>.</p>
|
|
<p>Example:</p>
|
|
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
|
<span class="w"> </span><span class="nt">"@context"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
|
<span class="w"> </span><span class="s2">"https://www.w3.org/ns/activitystreams"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="s2">"https://w3id.org/security/data-integrity/v1"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="s2">"https://w3id.org/fep/ef61"</span>
|
|
<span class="w"> </span><span class="p">],</span>
|
|
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Person"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ap://did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2/actor"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"inbox"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ap://did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2/actor/inbox"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"outbox"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ap://did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2/actor/outbox"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"gateways"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
|
|
<span class="w"> </span><span class="s2">"https://server1.example"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="s2">"https://server2.example"</span>
|
|
<span class="w"> </span><span class="p">],</span>
|
|
<span class="w"> </span><span class="nt">"proof"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
|
|
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"DataIntegrityProof"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"cryptosuite"</span><span class="p">:</span><span class="w"> </span><span class="s2">"eddsa-jcs-2022"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"created"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2023-02-24T23:36:38Z"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"verificationMethod"</span><span class="p">:</span><span class="w"> </span><span class="s2">"did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2#z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"proofPurpose"</span><span class="p">:</span><span class="w"> </span><span class="s2">"assertionMethod"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"proofValue"</span><span class="p">:</span><span class="w"> </span><span class="s2">"..."</span>
|
|
<span class="w"> </span><span class="p">}</span>
|
|
<span class="p">}</span>
|
|
</code></pre></div>
|
|
<h3 id="location-hints">Location hints<a class="headerlink" href="#location-hints" title="Permanent link">¶</a></h3>
|
|
<p>When ActivityPub object containing a reference to another actor is being constructed, implementations SHOULD provide a list of gateways where specified actor object can be retrieved. This list MAY be provided using the <code>gateways</code> query parameter. Each gateway address MUST be URI-encoded, and if multiple addresses are present they MUST be separated by commas.</p>
|
|
<p>Example:</p>
|
|
<div class="highlight"><pre><span></span><code>ap://did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2/actor?gateways=https%3A%2F%2Fserver1.example,https%3A%2F%2Fserver2.example
|
|
</code></pre></div>
|
|
<p>This URI indicates that object can be retrieved from two gateways:</p>
|
|
<ul>
|
|
<li><code>https://server1.example</code></li>
|
|
<li><code>https://server2.example</code></li>
|
|
</ul>
|
|
<div class="admonition important">
|
|
<p class="admonition-title">Important</p>
|
|
<p>When comparing 'ap' URIs, query parameters are discarded and canonical URIs are used.</p>
|
|
</div>
|
|
<h3 id="inboxes-and-outboxes">Inboxes and outboxes<a class="headerlink" href="#inboxes-and-outboxes" title="Permanent link">¶</a></h3>
|
|
<p>Portable inboxes and outboxes function as described in the <a href="https://www.w3.org/TR/activitypub/">ActivityPub</a> specification. These endpoints are also used to synchronize activities between gateways used by an actor.</p>
|
|
<p>Servers specified in the <code>gateways</code> property of an actor object MUST accept POST requests targeting its inbox collection.</p>
|
|
<p>Example:</p>
|
|
<div class="highlight"><pre><span></span><code>POST https://social.example/.well-known/apgateway/did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2/actor/inbox
|
|
</code></pre></div>
|
|
<p>Activities delivered to an inbox might be not portable. If the server does not accept deliveries on behalf of an actor, it MUST return <code>404 Not Found</code>.</p>
|
|
<p>Upon receiving an activity in actor's inbox, the server SHOULD forward it to inboxes located on other servers where actor's data is stored. An activity MUST NOT be forwarded from inbox more than once.</p>
|
|
<p>Servers specified in the <code>gateways</code> property of an actor object MAY accept POST requests targeting its outbox collection. Such servers MUST implement <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/ae97/fep-ae97.md">FEP-ae97</a>.</p>
|
|
<p>Activities delivered to an outbox are performed by a portable actor and therefore MUST be portable too. The server MUST verify them as described in section <a href="#authentication-and-authorization">Authentication and authorization</a> and then process them as described in <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/ae97/fep-ae97.md">FEP-ae97</a>. Clients MAY deliver activities to multiple outboxes, located on different servers.</p>
|
|
<p>Upon receiving an activity in actor's outbox, the server SHOULD forward it to outboxes located on other servers where actor's data is stored. An activity MUST NOT be forwarded from outbox more than once.</p>
|
|
<h2 id="collections">Collections<a class="headerlink" href="#collections" title="Permanent link">¶</a></h2>
|
|
<p>Collections identified by 'ap' URIs (including inbox and outbox collections) MAY be served without <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/8b32/fep-8b32.md">FEP-8b32</a> integrity proofs. Consuming implementations MUST NOT process unsecured collections attributed to a portable actor if they were retrieved from a server that is not listed in the <code>gateways</code> array of the actor document.</p>
|
|
<p>Portable collections can be filtered and paginated in a same way as non-portable <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/9f9f/fep-9f9f.md">collections</a>. A gateway MUST remove the integrity proof when generating a view of a collection created by a <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/ae97/fep-ae97.md">FEP-ae97</a> client.</p>
|
|
<h2 id="media">Media<a class="headerlink" href="#media" title="Permanent link">¶</a></h2>
|
|
<p>Integrity of an external resource is attested with a digest. When a portable object contains a reference to an external resource (such as image), it MUST also contain a <a href="https://w3c.github.io/vc-data-integrity/#resource-integrity"><code>digestMultibase</code></a> property representing the integrity digest of that resource. The digest MUST be computed using the SHA-256 algorithm.</p>
|
|
<p>The URI of an external resource SHOULD be a <a href="https://datatracker.ietf.org/doc/html/draft-sporny-hashlink-07">hashlink</a>.</p>
|
|
<p>Example of an <code>Image</code> attachment:</p>
|
|
<div class="highlight"><pre><span></span><code><span class="p">{</span>
|
|
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Image"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hl:zQmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"mediaType"</span><span class="p">:</span><span class="w"> </span><span class="s2">"image/png"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nt">"digestMultibase"</span><span class="p">:</span><span class="w"> </span><span class="s2">"zQmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n"</span>
|
|
<span class="p">}</span>
|
|
</code></pre></div>
|
|
<p>After retrieving a resource, the client MUST verify its integrity by computing its digest and comparing the result with the value encoded in <code>digestMultibase</code> property.</p>
|
|
<p>Resources attached to portable objects using hashlinks can be stored by gateways. To retrieve a resource from a gateway, the client MUST make an HTTP GET request to the gateway endpoint at <a href="https://datatracker.ietf.org/doc/html/rfc8615">well-known</a> location <code>/.well-known/apgateway</code>. The value of a hashlink URI MUST be appended to the gateway base URI.</p>
|
|
<p>Example of a request:</p>
|
|
<div class="highlight"><pre><span></span><code>GET https://social.example/.well-known/apgateway/hl:zQmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n
|
|
</code></pre></div>
|
|
<h2 id="compatibility">Compatibility<a class="headerlink" href="#compatibility" title="Permanent link">¶</a></h2>
|
|
<p><a name="compatible-ids"></a></p>
|
|
<h3 id="identifiers_1">Identifiers<a class="headerlink" href="#identifiers_1" title="Permanent link">¶</a></h3>
|
|
<p>'ap' URIs might not be compatible with existing <a href="https://www.w3.org/TR/activitypub/">ActivityPub</a> implementations. To provide backward compatibility, gateway-based HTTP(S) URIs of objects can be used instead of their canonical identifiers:</p>
|
|
<div class="highlight"><pre><span></span><code>https://social.example/.well-known/apgateway/did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2/path/to/object
|
|
</code></pre></div>
|
|
<p>Publishers MUST use the first gateway from actor's <code>gateways</code> list when constructing compatible identifiers. Consuming implementations that support 'ap' URIs MUST remove the part of the URI preceding <code>did:</code> and re-construct the canonical identifier. Objects with the same canonical identifier, but located on different gateways MUST be treated as different instances of the same object.</p>
|
|
<p>Publishers MUST NOT add the <code>gateways</code> query parameter to object IDs if compatible identifiers are used.</p>
|
|
<p>When HTTP signatures are necessary for communicating with other servers, each gateway that makes requests on behalf of an actor SHOULD use a separate secret key. The corresponding public keys MUST be added to actor document using the <code>assertionMethod</code> property as described in <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/521a/fep-521a.md">FEP-521a</a>.</p>
|
|
<div class="admonition warning">
|
|
<p class="admonition-title">Warning</p>
|
|
<p>If compatible identifiers are used, objects served by the same gateway will appear to have the same origin to implementations that do not support 'ap' URIs.</p>
|
|
</div>
|
|
<h3 id="webfinger-addresses">WebFinger addresses<a class="headerlink" href="#webfinger-addresses" title="Permanent link">¶</a></h3>
|
|
<p>WebFinger address of a portable actor can be obtained by the reverse discovery algorithm described in section 2.2 of <a href="https://swicg.github.io/activitypub-webfinger/">ActivityPub and WebFinger</a> report, but instead of taking the hostname from the identifier, it MUST be taken from the first gateway in actor's <code>gateways</code> array.</p>
|
|
<h2 id="discussion">Discussion<a class="headerlink" href="#discussion" title="Permanent link">¶</a></h2>
|
|
<p>(This section is non-normative.)</p>
|
|
<h3 id="discovering-locations">Discovering locations<a class="headerlink" href="#discovering-locations" title="Permanent link">¶</a></h3>
|
|
<h4 id="arbitrary-paths">Arbitrary paths<a class="headerlink" href="#arbitrary-paths" title="Permanent link">¶</a></h4>
|
|
<p>The <code>gateways</code> array can contain HTTP(S) URIs with a path component, thus enabling discovery based on the <a href="https://indieweb.org/follow_your_nose">"follow your nose"</a> principle, as opposed to discovery based on a <a href="https://datatracker.ietf.org/doc/html/rfc8615">well-known</a> location.</p>
|
|
<p>Example of a compatible object ID if the gateway endpoint is <code>https://social.example/ap</code>:</p>
|
|
<div class="highlight"><pre><span></span><code>https://social.example/ap/did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2/path/to/object
|
|
</code></pre></div>
|
|
<h4 id="alternatives-to-gateways-property">Alternatives to <code>gateways</code> property<a class="headerlink" href="#alternatives-to-gateways-property" title="Permanent link">¶</a></h4>
|
|
<p>This proposal makes use of the <code>gateways</code> property, but the following alternatives are being considered:</p>
|
|
<ul>
|
|
<li><code>gateways</code> property in actor's <code>endpoints</code> mapping</li>
|
|
<li><code>aliases</code> and <a href="https://schema.org/sameAs"><code>sameAs</code></a> (containing HTTP(S) URIs of objects)</li>
|
|
<li><code>alsoKnownAs</code> (used for account migrations, so the usage of this property may cause issues)</li>
|
|
<li><code>url</code> (with <code>alternate</code> <a href="https://html.spec.whatwg.org/multipage/links.html#linkTypes">relation type</a>)</li>
|
|
</ul>
|
|
<h4 id="did-services">DID services<a class="headerlink" href="#did-services" title="Permanent link">¶</a></h4>
|
|
<p>Instead of specifying gateways in actor document, they can be specified in <a href="https://www.w3.org/TR/did-core/">DID</a> document using <a href="https://www.w3.org/TR/did-core/#services">DID services</a>. This approach is not compatible with generative DID methods such as <code>did:key</code>, which might be necessary for some types of applications.</p>
|
|
<h3 id="media-access-control">Media access control<a class="headerlink" href="#media-access-control" title="Permanent link">¶</a></h3>
|
|
<p>The proposed approach to referencing media with hashlinks does not support access control: anybody who knows the hash can retrieve the file.</p>
|
|
<p>To work around this limitation, a different kind of identifier can be used where digest is combined with the <code>ap://</code> identifier of its parent document. The gateway will not serve media unless parent document ID is provided, and will check whether request signer has permission to view the document and therefore the attached media.</p>
|
|
<h2 id="implementations">Implementations<a class="headerlink" href="#implementations" title="Permanent link">¶</a></h2>
|
|
<ul>
|
|
<li><a href="https://codeberg.org/streams/streams/src/commit/6ec6780c7515a638b1ff818559af646fc8e21d94/FEDERATION.md#fediverse-feps">Streams</a></li>
|
|
<li><a href="https://codeberg.org/silverpill/mitra">Mitra</a> (gateway only)</li>
|
|
<li><a href="https://codeberg.org/silverpill/fep-ae97-client">fep-ae97-client</a> (client)</li>
|
|
<li><a href="https://codeberg.org/fortified/forte/src/commit/ade73e4ed05d0ea2b001abd8e3f2e94c856ac99f/FEDERATION.md#fediverse-feps">Forte</a></li>
|
|
<li><a href="https://github.com/dimkr/tootik/blob/v0.19.0/FEDERATION.md#data-portability">tootik</a></li>
|
|
</ul>
|
|
<h2 id="references">References<a class="headerlink" href="#references" title="Permanent link">¶</a></h2>
|
|
<ul>
|
|
<li>Christine Lemmer Webber, Jessica Tallon, <a href="https://www.w3.org/TR/activitypub/">ActivityPub</a>, 2018</li>
|
|
<li>S. Bradner, <a href="https://datatracker.ietf.org/doc/html/rfc2119.html">Key words for use in RFCs to Indicate Requirement Levels</a>, 1997</li>
|
|
<li>T. Berners-Lee, R. Fielding, L. Masinter, <a href="https://datatracker.ietf.org/doc/html/rfc3986.html">Uniform Resource Identifier (URI): Generic Syntax</a>, 2005</li>
|
|
<li>Manu Sporny, Dave Longley, Markus Sabadello, Drummond Reed, Orie Steele, Christopher Allen, <a href="https://www.w3.org/TR/did-core/">Decentralized Identifiers (DIDs) v1.0</a>, 2022</li>
|
|
<li>Dave Longley, Manu Sporny, Markus Sabadello, Drummond Reed, Orie Steele, Christopher Allen, <a href="https://www.w3.org/TR/cid/">Controlled Identifiers v1.0</a>, 2025</li>
|
|
<li>Dave Longley, Dmitri Zagidulin, Manu Sporny, <a href="https://w3c-ccg.github.io/did-key-spec/">The did:key Method v0.7</a>, 2022</li>
|
|
<li>M. Nottingham, <a href="https://datatracker.ietf.org/doc/html/rfc8615">Well-Known Uniform Resource Identifiers (URIs)</a>, 2019</li>
|
|
<li>silverpill, <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/8b32/fep-8b32.md">FEP-8b32: Object Integrity Proofs</a>, 2022</li>
|
|
<li>silverpill, <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/ae97/fep-ae97.md">FEP-ae97: Client-side activity signing</a>, 2023</li>
|
|
<li>silverpill, <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/fe34/fep-fe34.md">FEP-fe34: Origin-based security model</a>, 2024</li>
|
|
<li>A. Barth, <a href="https://www.rfc-editor.org/rfc/rfc6454.html">The Web Origin Concept</a>, 2011</li>
|
|
<li>Steve Bate, <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/ae49/fep-ae49.md">FEP-ae49: Semantic Routing for ActivityPub</a>, 2026</li>
|
|
<li>silverpill, <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/2277/fep-2277.md">FEP-2277: ActivityPub core types</a>, 2025</li>
|
|
<li>silverpill, <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/9f9f/fep-9f9f.md">FEP-9f9f: Collections</a>, 2026</li>
|
|
<li>M. Sporny, L. Rosenthol, <a href="https://datatracker.ietf.org/doc/html/draft-sporny-hashlink-07">Cryptographic Hyperlinks</a>, 2021</li>
|
|
<li>silverpill, <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/521a/fep-521a.md">FEP-521a: Representing actor's public keys</a>, 2023</li>
|
|
<li>a, Evan Prodromou, <a href="https://swicg.github.io/activitypub-webfinger/">ActivityPub and WebFinger</a>, 2024</li>
|
|
<li>Adam R. Nelson, <a href="https://codeberg.org/fediverse/fep/src/branch/main/fep/fffd/fep-fffd.md">FEP-fffd: Proxy Objects</a>, 2023</li>
|
|
<li>Jonne Haß, <a href="https://nodeinfo.diaspora.software/">NodeInfo</a>, 2014</li>
|
|
</ul>
|
|
<h2 id="copyright">Copyright<a class="headerlink" href="#copyright" title="Permanent link">¶</a></h2>
|
|
<p>CC0 1.0 Universal (CC0 1.0) Public Domain Dedication</p>
|
|
<p>To the extent possible under law, the authors of this Fediverse Enhancement Proposal have waived all copyright and related or neighboring rights to this work.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</article>
|
|
</div>
|
|
|
|
|
|
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
|
|
</div>
|
|
|
|
</main>
|
|
|
|
<footer class="md-footer">
|
|
|
|
<div class="md-footer-meta md-typeset">
|
|
<div class="md-footer-meta__inner md-grid">
|
|
<div class="md-copyright">
|
|
|
|
|
|
Made with
|
|
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
|
|
Material for MkDocs
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
</div>
|
|
<div class="md-dialog" data-md-component="dialog">
|
|
<div class="md-dialog__inner md-typeset"></div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<script id="__config" type="application/json">{"annotate": null, "base": "../..", "features": ["navigation.tabs"], "search": "../../assets/javascripts/workers/search.2c215733.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
|
|
|
|
|
|
<script src="../../assets/javascripts/bundle.79ae519e.min.js"></script>
|
|
|
|
<script src="../../javascripts/tablesort@5.3.0/tablesort.min.js"></script>
|
|
|
|
<script src="../../javascripts/tablesort.js"></script>
|
|
|
|
|
|
</body>
|
|
</html> |