Authentication
A graph app uses three credentials, each for a different step. None of them carries scopes: what a caller may do depends on which credential it presents.
| Credential | Looks like | Used for |
|---|---|---|
| Developer token | A ChirpAuth ID token | Registering and managing your app |
| Client id, plus client secret or PKCE verifier | graphapp-..., graphsecret-... | Exchanging an approval code, in the request body |
| Access token | graph-access-... | Reading on behalf of the person who approved |
People use a fourth, their own Social Graph sign-in, on the approval page. Your app cannot obtain or use it.
Developer token
Authorization: Bearer <ChirpAuth ID token>
- It must be a ChirpAuth ID token for a person, issued to Stackwell’s
developer command-line tool. Tokens issued to other ChirpAuth apps,
including yours, are refused with
401. - The person must hold a ChirpAuth developer account at the time of the call.
Social Graph asks ChirpAuth on every call, so a withdrawn developer account
stops working at once. Without one:
403{"error":"A registered developer account is required to register graph apps"}. If ChirpAuth can’t answer:503. - Machine tokens are refused.
- The status and secret-rotation calls change only apps you registered.
Not yet: outside developers cannot get a ChirpAuth developer account or the developer tool, so they cannot register an app.
Client credentials
Sent only to POST /api/graph/token, in the JSON body, never as a header:
{
"clientId": "graphapp-ab6bd084821c471eaab9ef7f83b09bf9",
"clientSecret": "graphsecret-...",
"authorizationCode": "graphcode-...",
"redirectUri": "https://acme.example/social-graph/callback"
}
- A
confidentialapp always proves itself withclientSecret. If its approval link carried acode_challenge, it sends the matchingcodeVerifieras well; the verifier never replaces the secret. - A
publicapp has no secret and always usescodeVerifier. - Keep the client secret on your server. Rotate it with
POST /api/graph/apps/{id}/rotate-secret(developer token); the old secret stops working at once.
See Approval for the PKCE rules.
Access token
Authorization: Bearer graph-access-...
- One per app and person, valid for 90 days; see Access tokens.
- It acts for the person who approved, on the endpoints under
/api/graph-access/. It can’t call the developer endpoints, and it can’t approve anything.
What each credential allows
| Action | Developer token | Access token |
|---|---|---|
Register an app (POST /api/graph/apps) | Yes | No |
| Change your app’s status, rotate its secret | Your apps only | No |
Exchange an approval code (POST /api/graph/token) | Not needed: client credentials in the body | Not needed |
Read the person and their connections (/api/graph-access/...) | No | Yes |
| Record or remove the person’s membership | No | Yes |
| Approve or deny an app | No | No: only the person, on the approval page |
No credential
| Path | What it is |
|---|---|
GET /health | Liveness |
GET /graph/authorize | The approval page a person opens in a browser; they sign in there |
POST /api/graph/token | The code exchange; it authenticates with the body, not a header |
curl -sS https://socialgraph.stackwell.tech/api/graph-access/me | grep -Fx '{"error":"unauthorized"}'
curl -fsS -o /dev/null https://socialgraph.stackwell.tech/graph/authorize
Calling from a browser
Social Graph answers cross-origin browser requests only from origins Stackwell has allowed. From any other origin, call it from your server or a native app.