OAuth 2.0
StudioBase implements the OAuth 2.0 authorization code grant (RFC 6749). A studio owner authorizes your application once; your application then holds tokens scoped to that single studio.
Client registration is invite-only. The StudioBase team issues your
client_id and client_secret and registers your exact redirect URIs.
Authorization endpoint
GET https://www.studiobase.org/oauth/authorize
Redirect the user's browser here to start the flow.
| Query parameter | Required | Description |
|---|---|---|
client_id | Yes | Your client identifier |
redirect_uri | Yes | Must exactly match a registered redirect URI (no prefix or wildcard matching) |
response_type | Yes | Must be code |
state | Recommended | Opaque value echoed back to you unchanged — use it for CSRF protection |
The user signs in with their StudioBase owner account (the request round-trips through login if needed), picks which studio to connect when they own more than one, and approves or denies the request. Authorizing also enables webhooks for the selected studio.
Approved: the browser is redirected to your redirect_uri with
code (an authorization code, prefix sbac_) and your state:
https://your.app/callback?code=sbac_…&state=…
Denied: the redirect carries error=access_denied and your state.
Authorization codes are single-use and expire after 10 minutes.
If client_id, redirect_uri, or response_type is missing or invalid,
the error is rendered inline and the browser is not redirected
(RFC 6749 §4.1.2.1).
Token endpoint
POST https://www.studiobase.org/api/oauth/token
Content-Type: application/x-www-form-urlencoded
Client credentials are sent in the request body (client_id +
client_secret). HTTP Basic client authentication is not supported.
Exchange an authorization code
| Body field | Required | Description |
|---|---|---|
grant_type | Yes | authorization_code |
code | Yes | The code from the redirect |
redirect_uri | Yes | The same redirect_uri used in the authorization request |
client_id | Yes | Your client identifier |
client_secret | Yes | Your client secret |
curl -X POST https://www.studiobase.org/api/oauth/token \
-d grant_type=authorization_code \
-d code=sbac_… \
-d redirect_uri=https://your.app/callback \
-d client_id=your_client_id \
-d client_secret=your_client_secret
Success (200):
{
"access_token": "sbat_…",
"refresh_token": "sbrt_…",
"token_type": "bearer",
"expires_in": 3600
}
Token responses are sent with Cache-Control: no-store. Store both tokens
securely — StudioBase stores only hashes and cannot show them again.
Refresh an access token
| Body field | Required | Description |
|---|---|---|
grant_type | Yes | refresh_token |
refresh_token | Yes | The refresh token from the original exchange |
client_id | Yes | Your client identifier |
client_secret | Yes | Your client secret |
Success (200): same shape as above, with a new access_token. The
refresh token does not rotate — the response echoes the same
refresh_token.
Access tokens expire after 3600 seconds (1 hour). Use the access token
as Authorization: Bearer sbat_… against the
Webhook Subscription API.
Error responses
Errors use RFC 6749 error codes in a JSON body, e.g.
{"error": "invalid_grant"}.
| HTTP | error | When |
|---|---|---|
| 400 | invalid_request | Body is not parseable form-encoded data |
| 400 | invalid_grant | Unknown, expired, or already-used code; redirect_uri mismatch; unknown or revoked refresh token |
| 400 | unsupported_grant_type | grant_type is not authorization_code or refresh_token |
| 401 | invalid_client | Missing or unknown client_id, or wrong client_secret |
| 429 | temporarily_unavailable | Rate limited (30 requests/min per IP) — honor Retry-After |
| 500 | server_error | Transient server failure — safe to retry |
Revocation
- Code replay defense: exchanging an authorization code a second time
fails with
invalid_grantand revokes the connection minted from that code, in case the code leaked. - Studio-initiated disconnect: studio owners can disconnect your
application at any time from Settings → Integrations → Webhooks.
Revocation immediately invalidates the connection's tokens (subsequent
API calls return
401 {"error": "invalid_token"}) and deactivates its webhook subscriptions.