Skip to main content
Every request to the SocialAPI /v1 endpoints requires a Bearer token in the Authorization header. The API accepts three token types.

Token types

Token typeWho uses itFormatValidation method
API keyExternal developers, API clientssapi_key_<hex> prefixSHA-256 lookup hash, then bcrypt verify against api_keys table
Auth service JWTDashboard frontend (Next.js)EdDSA/Ed25519 signed JWTSignature verified via JWKS endpoint on the auth service (cached 15 min)
OAuth 2.1 access tokenMCP clients (Claude, ChatGPT, Cursor)EdDSA/Ed25519 signed JWTSignature verified via the API’s own OAuth public key
The middleware detects the token type automatically. Tokens starting with sapi_key_ are treated as API keys. All other tokens are validated as JWTs: first against the auth service public key, then (if that fails) against the OAuth 2.1 public key.

API keys

API keys are the primary authentication method for external integrations.

Format

sapi_key_<62 hex characters>

Passing the key

Include the key in the Authorization header:
curl https://api.social-api.ai/v1/accounts \
  -H "Authorization: Bearer sapi_key_your_key_here"
If the key is missing or invalid, the API returns:
{
  "error": "invalid or inactive API key",
  "code": "unauthorized"
}

Creating keys

Keys are created in the dashboard under Keys > New Key, or via the API:
curl -X POST https://api.social-api.ai/v1/keys \
  -H "Authorization: Bearer $SOCAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Production App"}'
The full key is returned once in raw_key. Store it immediately. Subsequent reads only show a truncated preview like sapi_key_a1b2c....

Revoking keys

curl -X DELETE https://api.social-api.ai/v1/keys/<key-id> \
  -H "Authorization: Bearer $SOCAPI_KEY"
A revoked key stops working immediately for all requests.

Listing keys

curl https://api.social-api.ai/v1/keys \
  -H "Authorization: Bearer $SOCAPI_KEY"
The response includes preview (suffix only), is_active, and last_used_at.

Auth service JWTs (dashboard)

The SocialAPI dashboard authenticates users through a standalone auth service that issues EdDSA/Ed25519 signed JWTs. When a dashboard user makes an API call, their JWT is sent as a Bearer token. The API validates the JWT signature by fetching the auth service’s public key from its JWKS endpoint (AUTH_SERVICE_URL/internal/.well-known/jwks.json). The public key is cached for 15 minutes. The JWT’s sub (subject) claim contains the auth service user UUID, which is mapped to a user record in the API database via POST /v1/users/provision.
Before a dashboard user can call any endpoint, they must be provisioned via POST /v1/users/provision. This creates the user record that JWT authentication depends on. The dashboard calls this automatically after every login. If this record is missing, JWT-authenticated requests return 401 user not provisioned.

OAuth 2.1 access tokens (MCP clients)

MCP clients (Claude, ChatGPT, Cursor) authenticate via the API’s built-in OAuth 2.1 authorization server. After completing the OAuth flow (see OAuth guide), the client receives an EdDSA/Ed25519 signed JWT access token. These tokens look identical to auth service JWTs at the wire level, but they are signed with the API’s own OAuth private key (configured via OAUTH_JWT_PRIVATE_KEY) and contain a type: "oauth_access" claim. Access tokens expire after 1 hour. Use the refresh token to obtain a new access token without re-authorization.

How the middleware resolves tokens

  1. If the token starts with sapi_key_, it is validated as an API key (SHA-256 lookup hash, bcrypt verify).
  2. Otherwise, the token is validated as an auth service JWT (EdDSA signature check against the JWKS endpoint).
  3. If auth service JWT validation fails, the token is validated as an OAuth 2.1 access token (EdDSA signature check against the OAuth public key).
  4. If all checks fail, the request is rejected with 401.
All three paths result in the same internal representation: an APIKey record attached to the request context with the user’s ID and plan tier.

Security best practices

  • Never expose keys in frontend code. Keys must only be used server-side.
  • Use environment variables. Do not hardcode keys in source code.
  • Create one key per service. Revoke individual keys if compromised without disrupting others.
  • Monitor last_used_at. Unused keys should be revoked.
  • Rotate OAuth refresh tokens. The API enforces refresh token rotation. Each refresh grants a new token pair.