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
| Permission | What the person sees | What it gives your app |
|---|---|---|
openid | Account identifier | The person's id for your app (sub). Always included. |
profile | Public profile | Username, display name, avatar and the date the account was created. |
offline_access | Stay signed in | A 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.
| Permission | What the person sees | What it allows | Methods of unet.api that need it |
|---|---|---|---|
content:read | Read posts and profiles | Read 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:read | Search UNET | Search people, posts, hashtags and topics as the person. Cannot change anything. | search, searchFediverse |
notifications:read | Read your notifications | See likes, replies, mentions and new followers, and mark notifications as read. Direct messages and account or security notices are never shared. | markNotificationsRead, notifications |
library:read | Read your saved posts and likes | See the posts the person saved and the posts they liked. | likes, saved |
settings:read | Read your settings | See privacy, notification, feed and translation settings. Never password, security keys, sessions or two-factor setup. | fediverse, notInterestedItems, settings |
posts:write | Post as you | Publish 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:interact | Like, repost and comment | Like 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:write | Save posts | Save posts to the person's collection and remove them again. | save, unsave |
follows:write | Follow and unfollow | Follow 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:write | Edit your profile | Change 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:manage | Edit and delete your posts and comments | Edit, 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:manage | Block, mute and report | See 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:write | Change your settings | Change 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).