Scopes

Every permission UNET knows: what the person sees, what it allows, and which SDK methods need it. The method lists are generated from the SDK source.

A scope is a permission. Your app lists the ones it needs when it is created, asks for them in scopes, and the person sees them on the sign-in page. The server holds a new app to the scopes it registered. See Permissions for how to ask, check and add them.

Sign-in scopes

PermissionWhat the person seesWhat it gives your app
openidAccount identifierThe person's id for your app (sub). Always included.
profilePublic profileUsername, display name, avatar and the date the account was created.
offline_accessStay signed inA refresh token, so the session lasts until the person removes your app.

REST API scopes

Each call of unet.api names the one scope it needs. Without it the call fails with InsufficientScope. The "what the person sees" column is the title on the sign-in page.

PermissionWhat the person seesWhat it allowsMethods of unet.api that need it
content:readRead posts and profilesRead the public feed, profiles and individual posts exactly as the person would see them, including posts from private accounts they follow. Cannot post, like, follow or message.commentLikes, commentReposts, comments, fediverseActor, fediverseActorConnections, fediverseActorPosts, fediverseFeed, fediverseHashtag, fediversePost, fediverseThread, feed, followers, following, getComment, hashtagPosts, longForm, lookupFediverseActor, media, mediaLink, musicPlaylist, mutualConnections, placePosts, post, postLikes, postReposts, postSubscription, profile, replies, suggestedUsers, topicPosts, translatePost, userMusic, userReplies, userReposts
search:readSearch UNETSearch people, posts, hashtags and topics as the person. Cannot change anything.search, searchFediverse
notifications:readRead your notificationsSee likes, replies, mentions and new followers, and mark notifications as read. Direct messages and account or security notices are never shared.markNotificationsRead, notifications
library:readRead your saved posts and likesSee the posts the person saved and the posts they liked.likes, saved
settings:readRead your settingsSee privacy, notification, feed and translation settings. Never password, security keys, sessions or two-factor setup.fediverse, notInterestedItems, settings
posts:writePost as youPublish new posts in the person's name: text, photos, video, audio, GIFs and long posts. Cannot edit or delete posts, message people, follow anyone or change the account.createPost, gifs.search, gifs.trending, scheduledPosts, searchPlaces
posts:interactLike, repost and commentLike and repost posts and write comments in the person's name, and undo them. Cannot publish posts, message people or follow anyone.boostOnFediverse, comment, installStickerPack, like, likeComment, likeOnFediverse, notInterested, replyOnFediverse, repost, repostComment, stickerPack, stickerPacks, subscribeToPost, unboostOnFediverse, uninstallStickerPack, unlike, unlikeComment, unlikeOnFediverse, unrepost, unrepostComment, unsubscribeFromPost, uploadCommentImage, voteInFediversePoll
library:writeSave postsSave posts to the person's collection and remove them again.save, unsave
follows:writeFollow and unfollowFollow and unfollow people, and approve or decline follow requests on the account. Cannot post or message.acceptFollowRequest, follow, followOnFediverse, followRequests, rejectFollowRequest, removeFollower, subscribeToAuthor, unfollow, unfollowOnFediverse, unsubscribeFromAuthor
profile:writeEdit your profileChange display name, bio, links, profile photo and banner. Cannot change the username, password or security settings.addMusic, removeBanner, removeMusic, reorderMusic, searchMusic, updateProfile, uploadAvatar, uploadBanner
posts:manageEdit and delete your posts and commentsEdit, reschedule or delete posts and comments the person has published, including ones made outside the app. Cannot post, message or follow.deleteComment, deleteFediverseReply, deletePost, pinComment, pinPost, reschedulePost, unpinComment, unpinPost, updateComment, updateFediverseReply, updatePost
safety:manageBlock, mute and reportSee and change who the person blocked or muted, and report posts, comments or accounts for them. Blocking also removes follows between them.block, blockOnFediverse, blocks, fediverseBlocked, mute, muted, report, unblock, unblockOnFediverse, unmute
settings:writeChange your settingsChange privacy (private account, who can message, mention or reply), notification, feed and translation settings. Cannot change the username, password, two-factor, sessions or delete the account.addMutedKeyword, removeMutedKeyword, removeNotInterested, setFediverse, updateSettings

realtime() needs notifications:read for the notifications stream and content:read for the posts and feeds stream. userMusic() is a read of content:read: it returns the tracks on a profile.

Open to visitors

A few reads work without a session, so a visitor who has not signed in can see a public post or profile: post(), profile() and longForm(). Without a session the call goes out without a token, and the answer has no viewer state and at most the public fields. Everything else needs a signed-in person and its scope.

Methods that need no permission

These need only a session: signIn, handleRedirectCallback, restore, getUser, refreshUser, isSignedIn, signOut, onSessionChange, getAccessToken, getIdToken, getGrantedScopes, hasScope. The server-side verifyAccessToken and verifyIdToken need your App ID (and Secret) instead.

Keeping this page right

The method lists above are produced from the SDK source by the script below: it reads web/sdk/api.ts and, for each public method of UnetApi, collects the scope strings in its body. The result at the time of writing covers 117 method-to-scope pairs. Re-run it after the SDK changes and update the table.

The script
#!/usr/bin/env python3
"""Lists, for every public method of UnetApi in web/sdk/api.ts, the permission(s) named in its body (the scope strings passed to
get()/getOpen()/send() or checked by hand), and which methods also work without a session (getOpen).
Re-run:  python3 scopes.py /path/to/web/sdk/api.ts   ->  JSON {scope: [methods], "open": [methods], "none": [methods without a scope string]}"""
import re, sys, json
src = open(sys.argv[1], encoding='utf-8').read().split('\n')
start = next(i for i, l in enumerate(src) if l.startswith('export class UnetApi'))
SCOPE = re.compile(r'"((?:content|search|notifications|posts|follows|library|safety|profile|settings):(?:read|write|manage|interact))"')
bodies, cur, member = {}, None, None
for line in src[start:]:
    if line.startswith('}') : break
    m = re.match(r'^  (async )?([a-zA-Z]+)(?:<[^>]*>)?\(', line)
    if m and not line.lstrip().startswith('private'):
        cur = m.group(2); bodies.setdefault(cur, [])
    elif re.match(r'^  (?:private |readonly )?[a-zA-Z]+(?:<[^>]*>)? ?(?:=|:|\()', line) and not m:
        pm = re.match(r'^  (?:private |readonly )?([a-zA-Z]+) = \{', line)
        member = pm.group(1) if pm else None
        if not pm: cur = None
    if line.startswith('  private '): cur = None
    if line == '  };': member = None
    sm = re.match(r'^    ([a-zA-Z]+): (?:\(|async)', line)
    if member and sm: cur = f'{member}.{sm.group(1)}'; bodies.setdefault(cur, [])
    if cur: bodies[cur].append(line)
out, opens, none = {}, [], []
for name, lines in bodies.items():
    text = '\n'.join(lines)
    scopes = sorted(set(SCOPE.findall(text)))
    for s in scopes: out.setdefault(s, []).append(name)
    if 'getOpen' in text: opens.append(name)
    if not scopes: none.append(name)
res = {k: sorted(v) for k, v in sorted(out.items())}
res['open'] = sorted(opens); res['none'] = sorted(none)
print(json.dumps(res, indent=1))

Run it as python3 scopes.py path/to/web/sdk/api.ts. It prints JSON: one list of methods per scope, plus open (the methods that work without a session) and none (members with no scope string, such as constructor, realtime and withSignal).