Documentation Index
Fetch the complete documentation index at: https://docs.busha.io/llms.txt
Use this file to discover all available pages before exploring further.
PKCE is mandatory
Every authorization request must includecode_challenge and code_challenge_method=S256. Generate a fresh code_verifier (43–128 URL-safe characters) per authorization request. plain challenges and missing challenges are rejected.
PKCE ensures that an attacker who intercepts the authorization code cannot redeem it without also possessing the verifier, which never leaves your backend.
state is required for CSRF protection
Generate at least 16 bytes from a cryptographic RNG, bind the value to the user’s session, and reject any callback where the returned state does not match. Without this guard, an attacker can plant a known authorization code on someone else’s session.
nonce for OIDC ID tokens
When you request openid, include a nonce parameter in the authorization request and validate it inside the id_token. This protects against ID-token replay attacks.
redirect_uri must be exact
Register only redirect URIs your application controls. Production URIs must use HTTPS — HTTP is only allowed for localhost. Busha compares redirect_uri byte-for-byte:
https://app.example.com/cbandhttps://app.example.com/cb/are different URIs.- Port, scheme, path casing, and trailing slashes all matter.
- A mismatch is rejected immediately.
client_secret belongs in your backend
Never place client_secret in:
- A mobile application
- A single-page application
- A browser extension
- Any code that ships to users
Always verify access tokens before trusting them
Anyone can base64-decode a JWT and read its claims. None of those claims are trustworthy until you have verified the RS256 signature against the JWKS. See Token handling → Validating access tokens for the full validation checklist.Secure refresh token storage
Refresh tokens must be stored:- Encrypted at rest with row-level encryption keyed per user.
- Server-side only — never in browser cookies or
localStorage. - Persisted atomically — write the new pair before discarding the old one.
Revoke on disconnect
When a user disconnects your integration, callPOST /oauth2/revoke with token_type_hint=refresh_token. This immediately prevents new tokens from being minted. The currently-issued access token continues to be valid until exp, but no new session can be started.
Never log sensitive values
| Never log | Safe to log |
|---|---|
client_secret | client_id |
access_token | jti (JWT ID) |
refresh_token | sub (user UUID) |
code_verifier | Scope list |
Authorization code | Request / trace IDs |
id_token |