OAuth

Authorize an integration to access a customer's SnitchFeed organization on their behalf.

Integrations can access a customer's SnitchFeed data with OAuth 2.0 instead of asking the customer for an API key. The customer authorizes your integration, picks which organization to grant, and your integration gets short-lived access tokens scoped to just that organization and the permissions they approved.

Use OAuth when you're building an integration other customers will install. Use an API key when you're calling the API for your own single organization.

OAuth clients are provisioned by SnitchFeed. There is no self-serve client registration. Contact us to register your integration and get a client_id / client_secret.

Endpoints

All OAuth protocol endpoints are on the SnitchFeed API origin (https://api.snitchfeed.com), under /auth. Login, org selection, and consent UI run on the app (https://app.snitchfeed.com).

MethodPathDescription
GET/auth/oauth2/authorizeStart the authorization flow
POST/auth/oauth2/tokenExchange a code (or refresh token) for an access token
POST/auth/oauth2/revokeRevoke a token (RFC 7009)
GET/auth/.well-known/oauth-authorization-serverDiscovery metadata

Discovery: https://api.snitchfeed.com/auth/.well-known/oauth-authorization-server

Scopes

ScopeGrants
mentions:readGET /v1/mentions, /v1/mentions/{id}, /v1/mentions/count
listeners:readGET /v1/listeners, /v1/listeners/{id}
feeds:readGET /v1/feeds, /v1/feeds/{id}
org:readGET /v1/organization/context, /v1/organization/usage
offline_accessIssues a refresh token, so your app can stay connected until the customer revokes access

Request only the scopes your integration needs. They're shown to the customer on the consent screen. A client can only request scopes it was registered with; SnitchFeed enforces that ceiling at authorization time.

Tokens and org scope

  • Access tokens expire after 1 hour. Refresh tokens (if you requested offline_access) are valid for 30 days; authorization codes expire after 10 minutes, so exchange them immediately.
  • Each authorization grants access to exactly one organization: the one the customer picks at /oauth/select-org on the app. A token cannot span multiple organizations. To connect a second organization for the same customer, run the authorize flow again; they'll get another org picker.
  • There's no sandbox environment. Integrations are built and tested directly against production. Use a test organization if you don't want to touch real data while developing.

Authorize a customer

  1. Redirect the customer to /auth/oauth2/authorize with:

    ParamValue
    client_idYour client id
    redirect_uriMust exactly match one of your registered redirect URIs, including scheme and path. Registered URIs must be https:// (http:// is only accepted for localhost/127.0.0.1 during local development)
    response_typecode
    scopeSpace-separated scopes, e.g. mentions:read feeds:read offline_access
    resourcehttps://api.snitchfeed.com/v1 (RFC 8707 audience)
    stateOpaque value you'll verify on callback
    code_challenge, code_challenge_method=S256PKCE (required for all clients)
  2. The customer logs in (if needed), picks which of their organizations to connect, and approves the requested scopes on the consent screen.

  3. SnitchFeed redirects back to your redirect_uri with code and your state.

GET https://api.snitchfeed.com/auth/oauth2/authorize
  ?client_id=YOUR_CLIENT_ID
  &redirect_uri=https://yourapp.com/oauth/callback
  &response_type=code
  &scope=mentions:read%20feeds:read%20offline_access
  &resource=https://api.snitchfeed.com/v1
  &state=RANDOM_OPAQUE_STATE
  &code_challenge=YOUR_CODE_CHALLENGE
  &code_challenge_method=S256

Exchange the code for a token

curl -sS -X POST "https://api.snitchfeed.com/auth/oauth2/token" \
  -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
  -d "grant_type=authorization_code" \
  -d "code=THE_CODE_FROM_CALLBACK" \
  -d "redirect_uri=https://yourapp.com/oauth/callback" \
  -d "code_verifier=YOUR_PKCE_VERIFIER"

Client authentication is HTTP Basic (client_secret_basic) only. Send your client id and secret via -u/Authorization: Basic, not as body params.

{
  "access_token": "...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "...",
  "scope": "mentions:read feeds:read offline_access"
}

Call the API the same way you would with an API key. See Authentication:

curl -sS "https://api.snitchfeed.com/v1/organization/context" \
  -H "Authorization: Bearer THE_ACCESS_TOKEN"

Access tokens are opaque (not JWTs) and checked against SnitchFeed's servers on every request, so a revoked token stops working immediately. There's no caching lag to account for.

Refreshing

If you requested offline_access, exchange the refresh token for a new access token the same way:

curl -sS -X POST "https://api.snitchfeed.com/auth/oauth2/token" \
  -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=YOUR_REFRESH_TOKEN"

Rate limits

/auth/oauth2/authorize and /auth/oauth2/token are not rate limited. Once you're calling /v1/* with an access token, the usual per-organization rate limits apply (same limits as an API key, since they're enforced per organization rather than per credential).

Revoking access

Either side can end the connection:

  • Your app can revoke a token it holds via POST /auth/oauth2/revoke (token, plus your client credentials).
  • The customer can disconnect your app any time from their SnitchFeed workspace's connected apps list, without involving you.

If you registered a revoke webhook URL, SnitchFeed notifies your app when a customer disconnects so you can clean up stored tokens on your side. Deliveries are signed with X-SnitchFeed-Signature (HMAC-SHA256) and deduplicated with X-SnitchFeed-Delivery-Id.

Errors

These use the standard OAuth2 error / error_description shape, not the /v1 error envelope (that only applies to data API calls). The two OAuth endpoints deliver errors differently:

  • /auth/oauth2/authorize: once your client_id and redirect_uri are recognized, errors (access_denied, invalid_scope, invalid_request, etc.) come back as a redirect to your redirect_uri with error, error_description, and state as query params. There's no JSON body to read. If client_id or redirect_uri itself is invalid or unregistered, SnitchFeed can't safely redirect and shows an error page instead.
  • /auth/oauth2/token: errors are a JSON body with HTTP 400 (including for bad client credentials; invalid_client is 400 here, not 401). Common cases: invalid_grant (code, refresh token, or PKCE verifier didn't match, or the code already expired/was used), invalid_scope (requested a scope your client isn't registered for), invalid_client (bad client id/secret).

Once you're calling /v1/* with an access token, a revoked or expired token returns the usual 401 unauthorized from the data API.

On this page