Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Concepts

This page lists what Social Graph enforces today. Where something is missing, it says “Not yet”.

Graph apps

A graph app is your app’s registration with Social Graph. It has:

  • a client id (graphapp-...), which is public;
  • a client secret (graphsecret-...), for a confidential app only. It is shown once, at registration or when you rotate it. Social Graph stores only a hash of it. Rotating replaces it at once;
  • one redirect URI, where people’s browsers return after they decide;
  • a platform, web or native, and a client type, confidential (the default) or public.
PlatformRedirect URI
webhttps:// only
nativeA custom scheme with a host, such as acme://social-graph/callback. http and https are refused.

A public app (a mobile app, or code running in a browser) has no client secret and must use PKCE. A confidential app (one with a server) always sends its client secret, and may use PKCE as well.

A native app is identified only by its redirect URI and PKCE. Social Graph doesn’t check which installed app receives the redirect: another app on the phone can claim the same custom scheme. PKCE stops that app from using a code it intercepts from your app’s flow, but it can run its own flow under your client id.

An app’s status decides whether it can be used:

StatusMeaning
draftNew apps start here. Nobody can approve it, and approving returns 403 app_not_yet_active.
activePeople can approve it, and its access tokens work.
disabledSet by you. Approvals return 403 app_disabled, and all of its access tokens return 401 until you make it active again.

Stackwell can also suspend or end an app. Its approvals then return 403 (app_suspended or app_terminated), and its tokens return 401.

verified in an app’s record says whether Stackwell has reviewed it.

Not yet:

  • Self-serve registration for outside developers. See Authentication.
  • A way to change an app’s name, description or redirect URI after registering it.
  • Scopes. Every grant allows the same reads, listed under What a grant allows.

Approval

You send the person to https://socialgraph.stackwell.tech/graph/authorize with your client_id, redirect_uri, and optionally state and code_challenge (camelCase names work too).

  • The redirect_uri must exactly match the one you registered. If it doesn’t, or the app is not active, the page shows an error and sends the person nowhere.
  • The page shows the app’s registered name, description and redirect URI, never what the link claims.
  • If the person approves, their browser goes to your redirect URI with code and state. If they deny, it goes there with error=access_denied and state. state is passed back unchanged.
  • The code works once, for 5 minutes, only with the same client id and redirect URI. Using it twice returns 409.
  • PKCE: code_challenge is the base64url SHA-256 of a verifier you keep, without padding, 43 to 128 characters. SHA-256 is the only method; there is no code_challenge_method. If the approval carried a challenge, the code exchange needs the matching codeVerifier. A public app must send one. A confidential app always needs its clientSecret too: a verifier never replaces the secret.

Approving gives your app nothing until you exchange the code.

Access tokens

Exchanging a code returns an access token, graph-access-..., that lets your app read on behalf of the person who approved.

  • One token per app and person. Each new exchange for the same person replaces the previous token, which stops working.
  • 90 days. A token stops working 90 days after it was issued. To get a new one, send the person through approval again.
  • Revocation. A revoked token stops working at once. Not yet: the Social Graph web app has no screen where a person can see or revoke the apps they approved.
  • Social Graph stores only a hash of the token.
  • A token that has expired, been replaced or revoked, or belongs to an app that is not active, returns 401 with {"error":"unauthorized"}.

What a grant allows

With a person’s access token your app can:

  • read the person’s own profile: GET /api/graph-access/me;
  • list their connections: GET /api/graph-access/connections;
  • check whether they are connected to someone your app already knows: GET /api/graph-access/connections/{id}/status;
  • list the connections they share with that someone: GET /api/graph-access/connections/{id}/mutuals;
  • record your own id for the person, and list which of their connections your app has recorded: see Memberships.

A grant cannot create, change or remove connections, and it cannot read anyone else’s connections.

Identifiers

Your app sees each person under a psd_... id that belongs to your app. It stays the same for that person across calls and tokens. Another app sees different psd_ ids for the same people. Use these ids as your record of a person.

  • GET /api/graph-access/me and the code exchange’s me (POST /api/graph/token) return the approving person’s psd_ id.
  • Connection lists, mutuals and member lists return psd_ ids in userId.
  • /status and /mutuals take a psd_ id your app has been shown. An id your app has not been shown answers as “not connected” (connected: false, or an empty list), never as an error.

Display names and avatars are the same for every app. Not yet: a person cannot set their display name, so new accounts get a generated one such as user-5f1c0a9e, and avatarUrl is usually null.

Connections

A connection links two people, and both agreed to it. It has no direction: if A is connected to B, B is connected to A.

  • Some connections expire. An expired connection no longer appears in GET /api/graph-access/connections and /status reports it as not connected.
  • A person whose account Stackwell has ended does not appear in connection lists.
  • A person can limit your app to the connections they have given certain tags. Then every read above (connection lists, /status, /mutuals and member lists) shows only those connections, and /status reports any other connection as not connected. Your app never sees the tags. Not yet: there is no screen where a person sets this limit.
  • Connection lists are sorted by display name and hold at most 100 people. There is no paging.

Memberships

A membership is your app’s own id for a person, which your app records. It lets your app find which of a person’s connections also use your app.

  • POST /api/graph-access/membership records appUserId (required) and appDisplayName for the token’s person. Calling it again replaces them.
  • An appUserId can belong to only one person per app. Recording one that another person holds returns 409.
  • GET /api/graph-access/connections/members lists the token’s person’s connections that have a membership in your app, with their psd_ id and your appUserId. A connection appears only while their own grant to your app is in force: once they revoke it or it expires, their membership is left out until they approve your app again.
  • DELETE /api/graph-access/membership removes the token’s person’s membership.