OAuth 2.0
OAuth 2.0 is how a tool gets an API key for someone else's CrawlBrain account.
If you are building an integration, a plugin, or an internal tool used by more than one account, do not ask users to paste an API key. Ask them to click Authorize. After they sign in and approve your tool on a consent screen, your tool receives a key scoped to their account.
The CMS plugins and the browser extension use this flow.
The flow
It is a standard authorization-code grant in two steps.
Step 1: Send the user to the consent screen
GET https://app.crawlbrain.com/oauth/authorize
| Parameter | Required | Notes |
|---|---|---|
client_id |
yes | Your integration's name, up to 120 characters. Shown on the consent screen and used as the key's name |
redirect_uri |
yes | Where to send the user back |
state |
yes | Opaque value you generate. Verify it on return |
https://app.crawlbrain.com/oauth/authorize
?client_id=my-integration
&redirect_uri=https://mytool.example.com/callback
&state=RANDOM_STRING
The user signs in if they are not already, sees what your tool is asking for, and clicks Authorize. They are redirected to your redirect_uri with a one-time code:
https://mytool.example.com/callback?code=ONE_TIME_CODE&state=RANDOM_STRING
Check that state matches what you sent, and drop the request if it does not. That one-line check is what stops a cross-site request forgery on your callback.
Step 2: Exchange the code for a key
POST https://api.crawlbrain.com/v1/oauth/token
| Field | Required |
|---|---|
code |
yes |
client_id |
yes |
redirect_uri |
yes, and it must match step 1 exactly |
curl -X POST https://api.crawlbrain.com/v1/oauth/token \
-H "Content-Type: application/json" \
-d '{
"code": "ONE_TIME_CODE",
"client_id": "my-integration",
"redirect_uri": "https://mytool.example.com/callback"
}'
{
"access_token": "cb_...",
"token_type": "api_key",
"api_key_id": 42,
"header_name": "Api-Key"
}
access_token is a cb_ API key for that user's account. Store it the way you would store any credential, and use it in the Api-Key header from then on.
If the user clicks Deny, they come back to your redirect_uri with ?error=access_denied&state=... and no code.
No API key is needed to call the token endpoint. The user already consented in step 1, and the code proves it.
Rules on the code
- Single use. A second exchange of the same code fails.
- Short lived. It expires after 10 minutes. Exchange it immediately, server-side.
- The redirect_uri must match. Byte for byte, including trailing slashes.
Allowed redirect URIs
Any https:// redirect URI is allowed, on any host, up to 500 characters. For local development, http:// is allowed on localhost, 127.0.0.1 and [::1] only.
Browser extensions can use their https://<extension-id>.chromiumapp.org/ redirect, which is what chrome.identity.launchWebAuthFlow produces.
Plain http:// on a public host is rejected.
What the key can do
The key gives your tool the full API surface for that account, as long as Pro is active on it. Without Pro, API calls return 403 and there is nothing your tool can do about it except say so clearly.
Users can revoke your key at any time from Developer → API Keys. Handle a 401 by prompting them to reconnect, not by retrying in a loop.
Errors
The token endpoint returns 400 with a single error field:
| Error | Cause |
|---|---|
invalid_request |
code, client_id or redirect_uri is missing, or the redirect is not allowed |
invalid_grant |
The code is unknown, expired, already used, or was issued for another client_id or redirect_uri |
Legacy endpoint
Older WordPress plugins shipped with /auth/plugin?redirect=URL hardcoded. That URL still works and now shows the same consent screen.
New integrations should use /oauth/authorize.
Checklist
- [ ] Generate a fresh random
stateper attempt and verify it on return - [ ] Exchange the code server-side, never in the browser
- [ ] Store the key encrypted, never in logs
- [ ] Handle 401 by prompting reconnection
- [ ] Handle 403 by telling the user they need Pro
- [ ] Give users a disconnect action that forgets the key on your side