Skip to content

Instantly share code, notes, and snippets.

@HerbCaudill
Last active December 26, 2023 12:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save HerbCaudill/fafe808c69b24682770924ffeb2e4afa to your computer and use it in GitHub Desktop.
Save HerbCaudill/fafe808c69b24682770924ffeb2e4afa to your computer and use it in GitHub Desktop.
automerge-repo auth spec

localfirst/auth provider for Automerge Repo

This is pseudo-documentation for a hypothetical auth provider for Automerge Repo built around @localfirst/auth.

Configuration

A LocalFirstAuthProvider is configured with information about the local user and device.

import { LocalFirstAuthProvider, createUser, createDevice } from 'automerge-repo-auth-localfirstauth'

// Create the user & device, or retrieve them from storage.
// These objects include secret keys, so need to be stored securely.
const user = createUser('alice')
const device = createDevice(user.userId, 'ALICE-MACBOOK-2023')

const auth = new LocalFirstAuthProvider({ user, device })

const repo = new Repo({ network, storage, auth })

Shares

A "share" represents one or more documents that are shared with one or more other people. A share might include many documents shared with a long-lasting entity like a team. Or, it might represent a single document being shared with one other person.

Internally, a share is represented as a @localfirst/auth Team (even if it only contains two members) plus a set of associated documents. The team ID is used as the share ID.

Create a new share

When you create a share, you'll get back a unique ID.

const shareId = auth.createShare()

You can optionally provide a list of documents to add to the share.

const shareId = auth.createShare(documentIds)

Join an existing share

You'll need the shareId as well as an invitation seed.

auth.joinAsMember({ shareId, user, invitationSeed })

If you're a device joining a team with an invitation from an existing user:

auth.joinAsDevice({ shareId, device, invitationSeed })

Invite someone to a share

const { id, seed } = auth.inviteMember(shareId)

Send seed to the person you're inviting (along with the shareId) via a side channel (e.g. email, Signal, QR code). You can use id to revoke the invitation.

You can optionally provide an options object:

  • seed - A seed to use for the invitation. This is the secret that will be sent to the invitee, so longer is better. If not provided, a cryptographically random seed will be generated.
  • maxUses - The maximum number of times the invitation can be used. If not provided, the invitation can be used an unlimited number of times.
  • expiration - The time (expressed as a UNIX timestamp) at which the invitation expires. If not provided, the invitation will never expire.
const { id, seed } = auth.inviteMember(shareId, {
  seed: 'mediocre-millipede',
  maxUses: 3,
  expiration = (Date.now() + 30 * 60 * 1000) as UnixTimestamp, // 30 minutes
})

Add a device

const { id, seed } = auth.inviteDevice(shareId)

Send seed and shareId to the device by a side channel (e.g. bluetooth, QR code). You can use id to revoke the invitation.

You can optionally provide an options object:

  • seed - A seed to use for the invitation. This is the secret that will be sent to the invitee, so longer is better. If not provided, a cryptographically random seed will be generated.
  • expiration - The time (expressed as a UNIX timestamp) at which the invitation expires. If not provided, the invitation will expire in 30 minutes.

A device invitation can only be used once.

const { id, seed } = auth.inviteDevice(shareId, {
  seed: 'dextrous-dragonfly',
  expiration = new Date(Date.UTC(2020, 12, 25)).valueOf() as UnixTimestamp,
})

Permissions

Add documents to a share

const documentIds = [documentId1, documentId2]
auth.addDocuments(shareId, documentIds)

All documents must be added explicitly. If some documents reference other documents, you'll need to add the referenced documents as well.

All documents can be read and written by all share members.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment