Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mightynetworks.com/llms.txt

Use this file to discover all available pages before exploring further.

Alpha Release: The Headless API and its documentation are currently in alpha and subject to change. Schemas, fields, and behavior may be modified or updated without notice.

Overview

The Headless API authenticates requests with OAuth 2.0. A third-party application redirects a user to Mighty, the user signs in and approves a set of scopes, and your application receives a short-lived access token that acts on behalf of that user against the GraphQL API. This is fundamentally different from the Admin API, which uses a long-lived Bearer token tied to a network admin. Pick the one that matches your integration:
Admin APIHeadless API
Acts asA specific network adminAny authorized member, moderator, or host
CredentialLong-lived API tokenShort-lived OAuth 2.0 access token
Issued toA single admin userAn OAuth application + an end user
Use it forBack-office automation, integrations, analyticsUser-facing apps, mobile clients, agents, embeds

Why OAuth 2.0

The Headless API is designed for third-party applications that act on behalf of an end user — a member reading their feed in a custom mobile app, a host pulling their network into a back-office dashboard, an AI agent summarizing a space the user belongs to. The auth model has to answer two questions a static API key can’t:
  • Whose data is this? Every Headless API call resolves against a specific user’s permissions in a specific network. A member token can only see what that member can already see in the product; a host token additionally exposes host-level fields. There is no “superuser” mode and no way for a third-party app to read data the authorized user can’t.
  • Did the user actually consent? Before an application receives a token, the user is shown a consent screen listing the application name and the scopes it’s requesting, and explicitly approves. Mighty — not the application — collects the password. The application never sees the user’s credentials and can never act beyond the scopes the user approved.
OAuth 2.0 is the industry-standard protocol that solves both of these. Concretely, it gives us:
  • Delegated access without credential sharing. Users authorize applications through Mighty’s login flow. Applications never handle passwords, MFA codes, or session cookies.
  • Scoped, revocable tokens. Tokens are bound to a specific user, application, and scope set, with a short expiry. A leaked token has a small blast radius; users (and hosts) can revoke an application’s access without rotating their password.
  • A model that fits every client type. Server-side web apps use the Authorization Code flow with a client secret. Mobile, desktop, and single-page apps use Authorization Code + PKCE and ship no secret at all. Both target the same authorization server and the same token endpoint.
  • An ecosystem of tooling. OAuth 2.0 client libraries exist for every language and framework — there’s no Mighty-specific SDK to learn, and standard tools (Postman, curl, framework auth middleware) work out of the box. Mighty publishes the canonical endpoints at /.well-known/oauth-authorization-server per RFC 8414.
A static API key would have forced one of two bad shapes: either every integration acts as the host (no per-user permissions, no consent, full network read on a single leaked key), or every end user manually mints and pastes tokens (no consent UI, no revocation, no scope control, terrible UX). OAuth 2.0 is the off-the-shelf answer to “let third-party apps act as my users, with their consent, scoped to what they approved, revocable at any time.”

Create an OAuth application

Before your app can request tokens, a host or admin must register an OAuth application in the network. The application provides the Client ID (and, for confidential clients, Client Secret) you’ll use in the flows below, along with the redirect URIs and allowed scopes. For the full walkthrough — client types, redirect URI rules, scope catalog, secret rotation, and revocation — see OAuth Applications.

Endpoints

OAuth endpoints are served from the network’s community host, not from api.mn.co:
https://:network_subdomain.mn.co/oauth/authorize
https://:network_subdomain.mn.co/oauth/token
The canonical endpoint URLs are also advertised at:
https://:network_subdomain.mn.co/.well-known/oauth-authorization-server
per RFC 8414. Standard OAuth client libraries that support discovery will pick these up automatically.

Authorization Code flow

The standard flow for user-facing apps. Public clients (mobile, desktop, single-page) must add PKCE; confidential clients (server-side web apps) should use PKCE in addition to their client secret.

Step 1 — Redirect to the authorization endpoint

https://:network_subdomain.mn.co/oauth/authorize
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=YOUR_REDIRECT_URI
  &scope=SPACE_SEPARATED_SCOPES
  &state=RANDOM_OPAQUE_STRING
  &code_challenge=PKCE_CHALLENGE
  &code_challenge_method=S256
ParameterRequiredDescription
response_typeYesMust be code.
client_idYesThe Client ID from your OAuth application.
redirect_uriYesMust exactly match a URI registered on the application (scheme, host, port, path).
scopeYesSpace-separated list of scopes — see scopes.
stateYesCryptographically random per-request value. You must validate it on the redirect to prevent CSRF.
code_challengePublic clients (recommended for confidential)PKCE challenge derived from a code_verifier your app holds.
code_challenge_methodIf code_challenge is sentUse S256.

Step 2 — User approves

The user signs in (if they aren’t already) and approves the requested scopes on the consent screen. Mighty redirects back to your redirect_uri with:
https://app.example.com/oauth/callback?code=AUTH_CODE&state=YOUR_STATE
Validate that the returned state matches the value you generated. If it doesn’t, reject the callback — do not exchange the code.

Step 3 — Exchange the code for an access token

curl https://:network_subdomain.mn.co/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=AUTH_CODE_FROM_REDIRECT" \
  -d "redirect_uri=YOUR_REDIRECT_URI" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "code_verifier=PKCE_VERIFIER"
A successful response:
{
  "access_token": "eyJhbGciOi...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "def50200...",
  "scope": "read:userinfo read:posts"
}
The scope field reflects what was actually granted — the intersection of what the application is allowed to request, what the user approved, and what the user is permitted to do in the product. Always check it; don’t assume you got everything you asked for.

Step 4 — Call the Headless API

Pass the access token as a Bearer token on every GraphQL request:
POST /graphql HTTP/1.1
Host: api.mn.co
Authorization: Bearer eyJhbGciOi...
Content-Type: application/json

{ "query": "query { me { id name } }" }

Refreshing tokens

Access tokens are short-lived (expires_in is returned with each token, typically one hour). When a token expires, exchange the refresh token for a new pair:
curl https://:network_subdomain.mn.co/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=YOUR_REFRESH_TOKEN" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET"
Public clients omit client_secret. The response shape matches the original token response; the refresh token may rotate, so always persist the new value if one is returned. Refresh tokens are themselves long-lived but not permanent. They are invalidated when:
  • The user revokes the application’s access.
  • A host deletes the OAuth application.
  • The user changes their password or is signed out network-wide.
  • The refresh token reaches its absolute lifetime.
When a refresh attempt returns invalid_grant, the user must re-authorize — kick them back through Step 1.

Scopes and permissions

During the alpha, OAuth scopes are not enforced on the Headless API — tokens act with the underlying user’s full product permissions regardless of the scopes requested or granted. We’re still finalizing the exact scope catalog that will ship; build against the scopes documented here so your app is ready when enforcement turns on.
The access token grants exactly the access the underlying user has in the product, intersected with the scopes the user approved.
  • A read:posts scope granted to a member only exposes what the member could already see in the product.
  • A host:read:network_posts scope is only effective when the authorized user is a host of the network — a member who approves it still won’t get host-level reads.
If your authorization request includes any host scope (any scope prefixed host:), only hosts of the network will be able to complete sign-in. Members and moderators are blocked at the consent screen and cannot obtain a token. If your application needs to support both audiences, run two separate authorization flows: one with host scopes for host users, and one with only member scopes for everyone else.
For the full scope catalog and per-scope descriptions, see OAuth Applications — Scopes.

Errors

OAuth errors follow RFC 6749. The authorization endpoint returns errors via redirect query string; the token endpoint returns them as JSON with a 400 (or 401 for client auth failures).
ErrorWhereCommon cause
invalid_requestBothMissing or malformed parameter.
invalid_client/oauth/tokenWrong Client ID, wrong Client Secret, or sending a secret on a public client.
invalid_grant/oauth/tokenAuthorization code already used, expired, or redeemed against a different redirect_uri; PKCE verifier doesn’t match the challenge; refresh token revoked or expired.
unauthorized_clientBothThe application isn’t allowed to use this grant type.
unsupported_grant_type/oauth/tokengrant_type is not authorization_code or refresh_token.
invalid_scope/oauth/authorizeRequested a scope the application isn’t configured for.
access_denied/oauth/authorizeThe user declined the consent screen.
redirect_uri_mismatch/oauth/authorizeredirect_uri does not exactly match a registered URI.
For Headless GraphQL request errors (expired token, missing scope, insufficient permission), see the Headless API documentation.

Security best practices

  • Use PKCE everywhere. Required for public clients; recommended for confidential clients as defense in depth.
  • Validate state. Generate a cryptographically random state per authorization request and reject any callback whose state doesn’t match. This is your CSRF defense.
  • Pin redirect URIs. Register the exact URIs your app uses. Never register a wildcard, a path you don’t control, or an open redirector.
  • Treat the Client Secret like a password. Store it in a secret manager, never in source control, never in a client bundle. Never ship a secret in a mobile, desktop, or single-page app — use the public client type with PKCE instead.
  • Request least privilege. Ask for the narrowest scopes that let the feature work. Broader scopes drive higher consent abandonment and expand the blast radius if a token leaks.
  • Persist refresh tokens server-side. Refresh tokens are long-lived credentials. Store them encrypted at rest and never expose them to the browser or to logs.
  • Replace applications on suspicion of secret leak. During alpha, programmatic secret rotation is not yet available. If a secret may have leaked, delete the application (which revokes every token under it) and create a replacement.

Next steps

OAuth Applications

Register, configure, and manage the OAuth applications that issue tokens.

Headless API

Use your access token against the GraphQL API.