Skip to content

OAuth 2.0

Delegated, revocable account access for third-party apps - Authorization Code + PKCE.

When to use this instead of an API key

An API key is a long-lived secret you hold yourself - right for your own scripts and server-to-server integrations. OAuth is for a third-party app acting on a Reeloop user's behalf: the user approves access on a Reeloop-hosted consent screen, your app never sees their password or a static secret, and they can revoke access at any time from Settings β†’ Connected apps.

Reeloop implements Authorization Code with PKCE (RFC 6749 + RFC 7636) - the standard flow for web and native apps. There is one scope, full_access, matching exactly what an API key already grants (no granular per-route scopes yet). An OAuth access token works against both the public v1 REST API and the MCP server - pass it the same way you'd pass an API key.

Getting a client registered: from Settings β†’ Your OAuth apps, register your app's name and redirect URI(s) (1-5, https:// only) and you'll get a client_id/client_secret pair back - the secret is shown once, so copy it immediately. Growth/Pro plans only, same gate as API keys and the MCP server.

1. Send the user to the consent screen

GET https://reeloop.ai/oauth/authorize
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=https://yourapp.com/callback
  &code_challenge=BASE64URL(SHA256(code_verifier))
  &code_challenge_method=S256
  &scope=full_access
  &state=RANDOM_OPAQUE_VALUE

Generate code_verifier as a random string per RFC 7636 and keep it client-side until step 2. redirect_uri must exactly match one registered for your client. The user signs in (if needed), sees your app's name, and clicks Allow or Deny.

2. Exchange the code for tokens

Reeloop redirects to your redirect_uri with ?code=...&state=... (or ?error=access_denied if the user declined). Exchange the code immediately - it expires in 60 seconds and can only be used once:

POST https://reeloop.ai/api/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code &code=THE_CODE &redirect_uri=https://yourapp.com/callback &code_verifier=THE_ORIGINAL_VERIFIER &client_id=YOUR_CLIENT_ID &client_secret=YOUR_CLIENT_SECRET ```

{ "access_token": "oat_…", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "oar_…", "scope": "full_access" }

3. Call the API

Use the access token exactly like an API key:

Authorization: Bearer oat_your_access_token

It expires after 1 hour - use the refresh token to get a new pair before then:

POST https://reeloop.ai/api/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token &refresh_token=oar_your_refresh_token &client_id=YOUR_CLIENT_ID &client_secret=YOUR_CLIENT_SECRET ```

Refreshing rotates the refresh token - the old one stops working the moment you use it, so always store the new one from the response.

Revoking access

Either side can end a grant: the user from Settings β†’ Connected apps, or your app via the revocation endpoint (RFC 7009):

POST https://reeloop.ai/api/oauth/revoke
Content-Type: application/x-www-form-urlencoded

token=THE_ACCESS_OR_REFRESH_TOKEN &client_id=YOUR_CLIENT_ID &client_secret=YOUR_CLIENT_SECRET ```

Always returns 200 with an empty body, whether or not the token was valid.

Errors

Token/refresh/revoke errors use the standard OAuth shape (not the {error:{code,message}} envelope the rest of the API uses):

{ "error": "invalid_grant", "error_description": "The request was rejected - the code/token may be invalid, expired, or already used." }

What's not built yet

Granular per-route scopes (today it's all-or-nothing, same as an API key) and implicit/client-credentials/device-code grants - Authorization Code with PKCE is the only flow.

Start building

Create an API key in Settings β†’ API.

Start for free β†’

1 free video Β· no credit card