Skip to main content
Sonoran OAuth lets a user sign in to your application and approve specific access to their Sonoran account. Use the authorization code flow with PKCE (S256). Applications are public clients: there is no client secret.

Endpoints

For the Accounts profile and community API, use resource=https://accountapi.sonoransoftware.com throughout authorization, token exchange, and refresh. Existing Sonoran MCP integrations continue to use their own resource and product permissions.

Scopes

Request only what your integration needs. Scopes are separated by spaces and must be included in the client’s registration. Existing resource-specific scopes cad.admin.read, cad.admin.write, cms.read, and cms.write remain available for their corresponding Sonoran integrations. They do not grant subscription access in this API. Community lookup does not grant permission to administer a community or modify its subscription.

1. Register your application

Register once per application/environment and store the returned client_id. Supply one to ten complete callback URLs. Production web callbacks must use HTTPS. Credentials and URL fragments are rejected. Use an HTTPS callback on your application’s domain, as shown below. Native desktop clients may also use an HTTP IP loopback /callback URL.
The 201 response includes client_id, redirect_uris, and the allowed scope string. The optional client_uri is your application’s HTTPS website URL. Set logo_uri to a publicly accessible HTTPS image URL to display your application’s logo on the consent page. A square image works best; without a logo, Sonoran displays a generic application icon. Supplying a logo does not verify your application. Registration does not grant access to an account. Users must approve an authorization request. To add scopes to an existing integration, register a new client with those scopes; existing registrations and tokens are not automatically expanded.

2. Redirect the user to Sonoran

For each login, generate a cryptographically random state, nonce, and PKCE code_verifier. The verifier must be 43–128 characters using letters, digits, -, ., _, or ~. Set code_challenge to the base64url-encoded SHA-256 hash of that verifier, without padding. Keep the verifier and expected state/nonce tied to the user’s login attempt. Open the authorization endpoint with these URL-encoded query parameters:
Sonoran displays the account and requested permissions. Unverified callbacks show a warning; the user can choose Advanced, acknowledge the risk, then choose Allow access. Approved partner callbacks skip the warning and still require consent. Contact Sonoran support to request partner callback verification; developers cannot mark themselves verified. Callback verification does not change redirect matching: redirect_uri must exactly match a URL registered for this client. Only the listener port may vary for supported native IP loopback callbacks. Sonoran checks verification for the callback actually used in this request.

3. Validate the callback and exchange the code

After approval, the callback receives code, the original state, and iss=https://accountapi.sonoransoftware.com. Validate state against the login attempt and validate iss before exchanging the code. If the user cancels, handle error=access_denied.
The code expires after five minutes and is single-use. The exchange must use the same client, callback, resource, and matching PKCE verifier. The response includes access_token, token_type: "Bearer", expires_in: 900, granted scope, and resource. openid adds an id_token; offline_access adds a refresh_token. Validate ID tokens with the published signing keys, issuer, your client ID as audience, expiry, and original nonce. Use the stable sub as your user identifier. Use access tokens for API calls; never use an ID token as a bearer API token or put tokens in query strings.

4. Read the approved information

Example profile with openid profile:
Example community response (illustrative IDs):
The endpoint includes only products covered by granted *.communities.read scopes. Use ?product=cad, ?product=cms, or ?product=radio to request one product; requesting a product without its scope returns 403.
  • id is the product’s internal community identifier; treat it as an opaque string. Radio IDs may be numeric strings.
  • public_id is the community’s public ID. Use the product plus internal id as the integration key.
  • owner indicates registered ownership. status is owner or member; it is a relationship label, not an administrator permission or approval/banning status.
  • subscription is omitted entirely without that product’s *.subscriptions.read scope. tier is the product-reported version (for example FREE, PLUS, PRO, or a Sonoran One version); handle additional values and UNKNOWN. active reports the product’s subscription status.
  • An empty array means the selected products report no communities. Provider lookup failures return 503 (temporarily_unavailable), so do not treat a failed request as loss of membership or a downgrade.
These endpoints disclose no API keys, payment details, or Stripe subscription IDs. Memberships and subscription details are read again on each request. Cache briefly if needed and handle changes; the token’s scopes are not a permanent snapshot of community membership.

Refresh and disconnect

If you requested offline_access, refresh with form fields grant_type=refresh_token, client_id, refresh_token, and the same resource at /oauth2/token. Refresh tokens expire after 30 days. Each refresh returns a replacement token: store it atomically and never reuse the old one. Reusing an old refresh token revokes that token family. To disconnect, POST form fields client_id and token=YOUR_REFRESH_TOKEN to /oauth2/revoke. This revokes its refresh-token family. Already-issued access tokens expire after 15 minutes. Delete your locally stored tokens when the user disconnects.

Common errors