Skip to content

Auth (OAuth2 + PKCE)

User identity across the RBS ecosystem. The IdP is the CPR (Control Plane Router) at ecosystem.redbroomsoftware.com — every app is a client. Camino is NOT the issuer: its /oauth/* endpoints return 410 Gone (301 on /oauth/authorize) pointing here.

Status: LIVE (CPR since Topic 17 Phase 4D, 2026-05) Provider: CPR (ecosystem.redbroomsoftware.com) Source of truth: ecosystem-sdk/packages/api/api/oauth/*.ts + ecosystem-sdk/packages/api/lib/oauth-provider.tsread the code, do not replicate the flow in prose. This page states only the contract facts the discovery document gets wrong. Flow: OAuth2 Authorization Code with PKCE (RFC 7636, PKCE mandatory) Scopes: openid profile email ecosystem

⚠️ Contract facts every client MUST know (the discovery doc over-claims)

  1. Tokens are OPAQUE — 32-byte random hex, validated server-side by SHA-256 hash lookup. There is no JWT.
  2. id_token is NEVER issued. The token response is {access_token, token_type, expires_in, refresh_token, scope} (lib/oauth-provider.ts:369-377). Any code that decodes tokens.id_token fails 100% of the time (this broke Kiina F2, 2026-07-31).
  3. There is no JWKS. /.well-known/jwks.json → 404. The discovery document's jwks_uri and id_token_signing_alg_values_supported: ['RS256'] are a known over-claim (api/oauth/openid-configuration.ts:47,56, PD-S186-B / PD-197 Gap D).
  4. User identity comes ONLY from GET /oauth/userinfo with the Bearer access token: sub (stable — the CPR Supabase auth.users.id), email (omitted for phone-only users — key your grants accordingly), email_verified, name, picture, locale, and with scope ecosystem: organization_id, linked_accounts.
  5. Standard OIDC libraries (openid-client, next-auth) will fail on discovery-then-validate. Use RBSAuth from @r-bsoftware/ecosystem-sdk (issuer defaults to the CPR since 0.29.x) or a hand-rolled client that follows facts 1-4.

Endpoints (all on ecosystem.redbroomsoftware.com)

MethodPathPurpose
GET/.well-known/openid-configurationOIDC discovery (⚠️ see over-claims above)
GET/oauth/authorizeStart auth flow (PKCE required; 302 to /login without hub_session)
POST/oauth/tokenExchange code or refresh token (rotation on refresh)
GET/oauth/userinfoCurrent user (Bearer access token)
POST/oauth/revokeRevoke the user×client token pair + consent (⚠️ does NOT propagate to app-local sessions — PD-197 Gap E)

SDK helpers

ts
import { RBSAuth, generateState, validateState, createRBSCallbackHandler } from '@r-bsoftware/ecosystem-sdk'
  • SDK ≥0.29 defaults issuer to the CPR. Apps pinned to ≤0.20 (mancha packages/shared, cookie-monster, puppy-love) still default to Camino and work only via the 301 + token-exchange fallback — bump the SDK before "fixing" their issuer.
  • The callback factory's idpBaseUrls: [Camino, CPR] ordering is legacy dual-issue Phase 3; the Phase 4 cutover to CPR-first was never applied fleet-wide (PD-197).
  • The factory's identity-link POST (/api/ecosystem/identity/link) currently 404s against the CPR — no new ecosystem_user_links rows are produced anywhere (PD-197 Gap B).

Server-to-server

For partner apps that don't need a user session, use API keys instead:

http
Authorization: Bearer <api_key>

API keys are provisioned in Colectiva — contact api-support@redbroomsoftware.com.

Gotchas

  • Refresh tokens rotate. Every /oauth/token call with grant_type=refresh_token returns a new refresh token — persist it or lose the session.
  • State parameter is required. Use generateState() / validateState() from the SDK for CSRF protection.
  • Pre-registered clients only. OAuth clients live in oauth_clients in the CPR Supabase (shburtekrfoavfaeipgw), client_id convention rbs_<slug>_<hex16>. Registration runbook: kiina/docs/F2-APLICAR.md paso 2. Not self-service.
  • PKCE is mandatory for all flows.

History

Camino was the original IdP (retired Topic 17 Phase 4D; its oauth_clients rows were copied to the CPR in Phase 2). The user directory (auth.users) was unified into the CPR Supabase by PD-192 Opción A (S554) with preserved UUIDs, so sub == legacy camino_user_id for backfilled users. Remaining architectural gaps (new-Camino-user flow, dead identity-link producer, dual ecosystem_user_links copies, revocation propagation) are tracked as PD-197 in the memory pending-decisions queue.

Red Broom Software Ecosystem