SocialAPI uses OAuth in two distinct contexts:
- Connecting platform accounts (Instagram, Facebook, etc.) to your SocialAPI account so you can manage them through the API.
- Authenticating MCP/API clients (Claude, ChatGPT, Cursor) via the built-in OAuth 2.1 authorization server so they can call the API on your behalf.
Most social platforms use OAuth 2.0. Connecting a platform account takes three steps.
Step 1: Initiate the flow
Call POST /v1/accounts/connect with the platform and a redirect_uri:
curl -X POST https://api.social-api.ai/v1/accounts/connect \
-H "Authorization: Bearer $SOCAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"platform": "instagram",
"metadata": {
"redirect_uri": "https://app.example.com/oauth/callback"
}
}'
Response (HTTP 202):
{
"auth_url": "https://www.instagram.com/oauth/authorize?client_id=...&state=...",
"state": "4a8f2c1e9b3d7f06a5c2e8b4d1f3a7e2"
}
Step 2: Redirect the user
Send your user to auth_url. They log in and grant permissions. The platform redirects back to your redirect_uri with ?code=...&state=... query parameters.
Store the state value from Step 1. You need it in Step 3.
Step 3: Exchange the code
curl -X POST https://api.social-api.ai/v1/oauth/exchange \
-H "Authorization: Bearer $SOCAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"platform": "instagram",
"code": "AQDtbPB9X...",
"metadata": {
"state": "4a8f2c1e9b3d7f06a5c2e8b4d1f3a7e2",
"redirect_uri": "https://app.example.com/oauth/callback"
}
}'
Response (HTTP 201):
{
"account_id": "acc_01HZ9X3Q4R5M6N7P8V2K0W1J",
"platform": "instagram",
"username": "acmecorp"
}
The account_id is now ready to use in all account endpoints.
The state token is one-time-use and expires after 10 minutes. If the exchange fails with invalid or expired state, restart from Step 1.
State token security
The state value is a CSRF token. It:
- Is generated server-side as 16 random bytes (not guessable)
- Is stored in Redis with a 10-minute TTL
- Is deleted immediately on exchange (prevents replay attacks)
- Is tied to your API key. Another key cannot use your state.
If your /oauth/exchange call returns 403 state does not belong to this API key, the key used in Step 3 is different from the one used in Step 1.
Listing connected accounts
curl https://api.social-api.ai/v1/accounts \
-H "Authorization: Bearer $SOCAPI_KEY"
Reconnecting an account
If you call POST /v1/accounts/connect for an account that is already connected, the upsert updates the stored token. This is safe to call when tokens expire.
Some platforms accept an API key or credentials directly. For these, POST /v1/accounts/connect returns HTTP 201 immediately without a redirect:
curl -X POST https://api.social-api.ai/v1/accounts/connect \
-H "Authorization: Bearer $SOCAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"platform": "trustpilot",
"metadata": {
"api_key": "your-trustpilot-api-key"
}
}'
Check the Connectors section for each platform’s auth type and required metadata fields.
OAuth 2.1 for MCP and API clients
SocialAPI includes a built-in OAuth 2.1 authorization server that enables MCP clients (Claude, ChatGPT, Cursor) and other third-party applications to authenticate users and call the API on their behalf.
The implementation follows these RFCs:
- RFC 8414 for authorization server metadata discovery
- RFC 7591 for dynamic client registration
- RFC 7636 for PKCE (required)
- RFC 7009 for token revocation
Discovery
Clients can discover the authorization server configuration at:
GET /.well-known/oauth-authorization-server
Response:
{
"issuer": "https://api.social-api.ai",
"authorization_endpoint": "https://api.social-api.ai/oauth/authorize",
"token_endpoint": "https://api.social-api.ai/oauth/token",
"registration_endpoint": "https://api.social-api.ai/oauth/register",
"revocation_endpoint": "https://api.social-api.ai/oauth/revoke",
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"token_endpoint_auth_methods_supported": ["client_secret_post"],
"code_challenge_methods_supported": ["S256"],
"scopes_supported": ["social:all"]
}
Step 1: Register a client
Register your application using dynamic client registration:
curl -X POST https://api.social-api.ai/oauth/register \
-H "Content-Type: application/json" \
-d '{
"client_name": "My MCP Client",
"redirect_uris": ["https://app.example.com/callback"]
}'
Response (HTTP 201):
{
"client_id": "a1b2c3d4e5f6...",
"client_secret": "s3cr3t...",
"client_name": "My MCP Client",
"redirect_uris": ["https://app.example.com/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "client_secret_post"
}
The client_secret is returned once. Store it securely. It cannot be retrieved again.
Step 2: Authorize the user
Redirect the user to the authorization endpoint with PKCE parameters:
GET /oauth/authorize
?client_id=a1b2c3d4e5f6...
&redirect_uri=https://app.example.com/callback
&response_type=code
&scope=social:all
&state=random_csrf_value
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
The API validates the client and redirect URI, then redirects the user to the SocialAPI dashboard consent screen. After the user approves, they are redirected back to your redirect_uri with ?code=...&state=....
PKCE is required. The only supported challenge method is S256. Requests without a code_challenge are rejected with 400.
Single scope. The only supported scope is social:all, which grants full access to the user’s account. This is the default if no scope is specified.
Step 3: Exchange the code for tokens
curl -X POST https://api.social-api.ai/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTH_CODE_HERE" \
-d "client_id=a1b2c3d4e5f6..." \
-d "client_secret=s3cr3t..." \
-d "code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" \
-d "redirect_uri=https://app.example.com/callback"
Response:
{
"access_token": "eyJhbGciOiJFZERTQSIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "rt_a1b2c3d4...",
"scope": "social:all"
}
The access token is an EdDSA/Ed25519 signed JWT valid for 1 hour. Use it as a Bearer token for all /v1 endpoints.
Step 4: Refresh the access token
When the access token expires, use the refresh token to get a new pair:
curl -X POST https://api.social-api.ai/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=rt_a1b2c3d4..." \
-d "client_id=a1b2c3d4e5f6..."
The response contains a new access token and a new refresh token. The old refresh token is invalidated (rotation is enforced). Refresh tokens expire after 30 days.
Revoking tokens
To revoke a refresh token (for example, on user logout):
curl -X POST https://api.social-api.ai/oauth/revoke \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=rt_a1b2c3d4..." \
-d "client_id=a1b2c3d4e5f6..."
Per RFC 7009, this endpoint always returns 200, even if the token is already invalid.
Supporting endpoints
| Endpoint | Method | Purpose |
|---|
/.well-known/oauth-authorization-server | GET | RFC 8414 metadata discovery |
/oauth/register | POST | RFC 7591 dynamic client registration |
/oauth/authorize | GET | Authorization with PKCE |
/oauth/authorize/request | GET | Fetch pending authorization request details (used by dashboard) |
/oauth/authorize/confirm | POST | Consent confirmation (called by dashboard, requires auth service JWT) |
/oauth/token | POST | Code exchange and refresh token rotation |
/oauth/revoke | POST | RFC 7009 token revocation |
MCP server card
MCP clients can discover SocialAPI as a tool provider via the server card:
GET /.well-known/mcp/server-card.json
The protected resource metadata (RFC 9470) is available at:
GET /.well-known/oauth-protected-resource
GET /.well-known/oauth-protected-resource/mcp