Skip to content

Comments

feat: add public API foundation with OAuth2 authentication (CM-965)#3841

Merged
skwowet merged 25 commits intomainfrom
feat/CM-965
Feb 23, 2026
Merged

feat: add public API foundation with OAuth2 authentication (CM-965)#3841
skwowet merged 25 commits intomainfrom
feat/CM-965

Conversation

@skwowet
Copy link
Member

@skwowet skwowet commented Feb 11, 2026

Context

CDP is expanding beyond internal frontend usage. LFX One will consume CDP data through new transactional APIs for identity, role, and work experience verification. This PR lays the authentication, error handling, and routing foundation that all future public endpoints will build on.

The auth setup is based on Eric’s proposal: Auth0 client credentials (M2M) grant, where the LFX Angular SSR backend acts as a machine client. CDP trusts Auth0 as the IdP and never handles credential rotation directly. Scopes are statically defined in Auth0/Terraform and enforced per-endpoint.

What Changed

  • Added a new public API surface under backend/src/api/public with versioned routing (/api/v1/...).
  • Introduced OAuth2 token validation for public endpoints using express-oauth2-jwt-bearer.
  • Added an auth-agnostic Actor model (req.actor) and token-to-actor resolution (sub/azp + scopes), so handlers rely on identity abstraction, not raw tokens.
  • Added scope-based authorization middleware (requireScopes) and centralized scope definitions (security/scopes.ts), including scopes for members, identities, roles, work experiences, and project affiliations.
  • Added a dedicated public API error handler that maps Auth0/JWT errors and returns consistent structured JSON errors.
  • Mounted publicRouter at /api in backend/src/api/index.ts before internal tenant/segment route flow, so public endpoints run with their own auth/error pipeline and stay isolated from internal middleware assumptions.
  • Added Auth0 config plumbing for this flow (issuerBaseURL, audience) in config types/env mappings.
  • Added a first lightweight v1 endpoint scaffold (identities) as a foundation wiring check.

Cross-cutting Improvements Included

  • Standardized HTTP error model in @crowd/common (HttpError + concrete classes), while keeping legacy error classes under deprecated.
  • Updated rate limiting to return structured 429 responses via RateLimitError.
  • Updated webhook/search-sync/nango error middleware usage to align with HttpError JSON shape.
  • Added small ESLint/no-unused-vars cleanup support for underscore-prefixed ignored vars.
  • Added dependency/config updates required for OAuth2 flow.

Why These Decisions

  • Keeps this work aligned with the LFX One auth model: machine user + static scopes from Auth0 client grants.
  • Establishes a modern, typed, and composable foundation (actor + scopes + structured errors) for external APIs.
  • Avoids risky refactors of existing internal APIs right now; instead, builds a stable public pattern first, then enables gradual convergence later.

Out of Scope in This PR

  • Data model / DB schema changes for transactional operations.
  • Full endpoint implementation from spec (business logic, transactional writes, audit trail behavior).
  • Migration of internal endpoints to the new stack.

Next Steps

  • Implement schema/data model changes for verification + audit requirements.
  • Build spec endpoints incrementally on top of this foundation (members/search, identities/roles/work experiences flows).
  • Add transaction + audit behavior for write operations.

Note

Medium Risk
Introduces a new externally-consumable API surface with OAuth2/JWT validation and scope enforcement; misconfiguration or middleware ordering issues could unintentionally expose or block endpoints. Also changes error/429 response shapes across multiple services, which may affect clients expecting plain-text errors.

Overview
Adds a new public API surface under backend/src/api/public with versioned routing (/v1) protected by Auth0 OAuth2 JWT validation (express-oauth2-jwt-bearer), an Actor identity abstraction on req.actor, and per-route scope enforcement via requireScopes and centralized SCOPES.

Mounts the publicRouter() before the existing internal auth/tenant middleware stack, and wires new Auth0 config (issuerBaseURL, audience) into env/config types. Standardizes structured JSON HTTP errors across the backend and webhook/search-sync/nango services by introducing HttpError classes (including RateLimitError) and updating rate limiting and various handlers to return { error: { code, message } } instead of string messages; legacy error classes are moved under errors/deprecated.

Written by Cursor Bugbot for commit 49d0dab. This will update automatically on new commits. Configure here.

@skwowet skwowet self-assigned this Feb 11, 2026
@skwowet skwowet requested a review from themarolt February 19, 2026 15:08
@skwowet skwowet marked this pull request as ready for review February 19, 2026 15:09
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

@skwowet skwowet requested a review from mbani01 February 20, 2026 11:56
Copy link
Contributor

@mbani01 mbani01 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work @skwowet, left some non-blocking questions

@skwowet skwowet merged commit 4a84072 into main Feb 23, 2026
16 checks passed
@skwowet skwowet deleted the feat/CM-965 branch February 23, 2026 12:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants