Authentication
Borough supports two authentication methods: API keys (simplest) and OAuth 2.1 (for MCP clients and third-party integrations).
API Key (Bearer Token)
Section titled “API Key (Bearer Token)”Include your API key in the Authorization header:
Authorization: Bearer BOROUGH-<your-license-key>Keys use the format BOROUGH-<uuid> and are provisioned automatically when you subscribe to a plan.
BOROUGH-a1b2c3d4-e5f6-7890-abcd-ef1234567890Keys are validated against Polar.sh and cached for 10 minutes. If your key is revoked, cached access stops within 10 minutes.
OAuth 2.1 (PKCE)
Section titled “OAuth 2.1 (PKCE)”Borough implements OAuth 2.1 with PKCE for secure delegated access. This is the recommended method for MCP clients and third-party apps.
Endpoints
Section titled “Endpoints”| Endpoint | Method | Description |
|---|---|---|
/oauth/register | POST | Dynamic client registration (RFC 7591) |
/oauth/authorize | GET | Consent page (redirects user) |
/oauth/authorize | POST | Submit API key, receive auth code |
/oauth/token | POST | Exchange code for tokens |
/.well-known/oauth-authorization-server | GET | Server metadata (RFC 8414) |
/.well-known/oauth-protected-resource | GET | Resource metadata (RFC 9728) |
-
Register your client (optional for localhost apps):
Terminal window curl -X POST https://borough.qwady.app/oauth/register \-H "Content-Type: application/json" \-d '{"client_name":"My App","redirect_uris":["https://myapp.com/callback"]}'Unregistered clients may only use
localhostredirect URIs. -
Redirect user to authorize:
GET /oauth/authorize?response_type=code&client_id=<client_id>&redirect_uri=<redirect_uri>&code_challenge=<S256_challenge>&code_challenge_method=S256&state=<random_state>The user enters their Borough API key (or continues with Free tier) and is redirected back with an authorization code.
-
Exchange code for tokens:
Terminal window curl -X POST https://borough.qwady.app/oauth/token \-d "grant_type=authorization_code&code=<code>&client_id=<client_id>&code_verifier=<verifier>&redirect_uri=<redirect_uri>" -
Use the access token:
Authorization: Bearer <access_token>
Token lifetimes
Section titled “Token lifetimes”| Token | Lifetime |
|---|---|
| Access token | 1 hour |
| Refresh token | 30 days |
| Auth code | 5 minutes |
| Client registration | 30 days |
Use the refresh token to get new access tokens without re-authorization:
curl -X POST https://borough.qwady.app/oauth/token \ -d "grant_type=refresh_token&refresh_token=<token>&client_id=<client_id>"The refresh flow re-validates your API key, so tier changes and revocations take effect on the next refresh.
Free-tier access
Section titled “Free-tier access”Search endpoints (/v1/search/rentals, /v1/search/sales), areas (/v1/areas), and market endpoints work without authentication. Unauthenticated requests are subject to:
- 10 requests/minute rate limit (IP-based)
- 100 requests/month quota
- Maximum 10 results per page
Error responses
Section titled “Error responses”| Code | Status | Description |
|---|---|---|
MISSING_API_KEY | 401 | No Authorization header provided on a protected endpoint |
INVALID_API_KEY | 401 | Key doesn’t match any active subscription |
EXPIRED_API_KEY | 401 | Subscription has ended |
TIER_RESTRICTED | 403 | Endpoint requires a higher tier |
On 401 responses, the WWW-Authenticate header includes a link to the protected-resource metadata for automatic OAuth discovery.
Security best practices
Section titled “Security best practices”- Store keys in environment variables, never in client-side code
- Rotate keys by creating a new subscription if compromised
- Use the minimum tier needed for your use case
- For OAuth, always use PKCE with S256 code challenges
- Register your client to restrict allowed redirect URIs