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 aconfidentialapp 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,
webornative, and a client type,confidential(the default) orpublic.
| Platform | Redirect URI |
|---|---|
web | https:// only |
native | A 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:
| Status | Meaning |
|---|---|
draft | New apps start here. Nobody can approve it, and approving returns 403 app_not_yet_active. |
active | People can approve it, and its access tokens work. |
disabled | Set 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_urimust exactly match the one you registered. If it doesn’t, or the app is notactive, 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
codeandstate. If they deny, it goes there witherror=access_deniedandstate.stateis 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_challengeis the base64url SHA-256 of a verifier you keep, without padding, 43 to 128 characters. SHA-256 is the only method; there is nocode_challenge_method. If the approval carried a challenge, the code exchange needs the matchingcodeVerifier. Apublicapp must send one. Aconfidentialapp always needs itsclientSecrettoo: 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, returns401with{"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/meand the code exchange’sme(POST /api/graph/token) return the approving person’spsd_id.- Connection lists, mutuals and member lists return
psd_ids inuserId. /statusand/mutualstake apsd_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/connectionsand/statusreports 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,/mutualsand member lists) shows only those connections, and/statusreports 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/membershiprecordsappUserId(required) andappDisplayNamefor the token’s person. Calling it again replaces them.- An
appUserIdcan belong to only one person per app. Recording one that another person holds returns409. GET /api/graph-access/connections/memberslists the token’s person’s connections that have a membership in your app, with theirpsd_id and yourappUserId. 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/membershipremoves the token’s person’s membership.