mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-28 05:12:33 +00:00
* fix(auth): update RPC method names for authentication calls Refactor authentication-related RPC method names to use underscores instead of dots for consistency. Updated methods include `get_state`, `get_session_token`, `clear_session`, and `store_session`. chore: update OpenHuman version to 0.51.19 style: standardize string formatting in quickjs_libs/bootstrap.js and other files - Replace single quotes with double quotes for string literals in various functions. - Ensure consistent formatting across console logging and error handling. fix(config): improve token retrieval logic in ops_core.rs - Enhance the logic for retrieving the active session token from the credentials store, accommodating user-specific directories. * test: align auth and OAuth assertions with current behavior Update stale test expectations for underscore-style auth RPC methods and light-theme OAuth button classes, and make the bypass-login E2E assertion resilient to the current auth persistence model. Made-with: Cursor * chore: apply formatter output for login flow spec Include Prettier formatting adjustments produced by the pre-push hook so the branch can pass repository push checks cleanly. Made-with: Cursor
6.1 KiB
6.1 KiB
Proxy Route Flow (src/routes/proxy.ts)
This document explains how proxy requests move through the backend when calling:
/proxy/by-id/:integrationId/{*path}/proxy/encrypted/:integrationId/{*path}
Both endpoints let clients call third-party provider APIs (Google, Notion, etc.) through our backend while enforcing ownership checks, path restrictions, and token handling.
High-level architecture
src/routes/proxy.ts is the HTTP entrypoint. It:
- Authenticates the user via JWT
- Applies per-user rate limiting (100 requests/minute)
- Normalizes request params, headers, and query
- Delegates to controller logic:
- non-encrypted flow:
forwardByIntegrationId(...) - encrypted flow:
forwardWithEncryptedTokens(...)
- non-encrypted flow:
- Returns upstream status/body with a safe subset of headers
Shared route behavior
Both routes in src/routes/proxy.ts share these behaviors:
authenticateJWTmiddleware requires a valid bearer token.proxyRateLimitlimits calls by authenticated user ID (falls back to IP).integrationIdis validated for presence in the route handler.- wildcard
{*path}is normalized into a leading-slash path (for example,v1/users/me->/v1/users/me). - query and headers are normalized into
Record<string, string>usingtoSingleValueRecord.
Flow A: /proxy/by-id/:integrationId/{*path} (standard token storage)
Route layer (src/routes/proxy.ts)
- Extracts
integrationIdand wildcardpath. - Builds a
ProxyRequestobject:methodpath- normalized
query - normalized
headers body
- Calls
forwardByIntegrationId(integrationId, userId, request). - Sets returned headers and forwards status/data to the client.
Controller layer (src/controllers/proxy/forward.ts)
forwardByIntegrationId(...):
- Validates ObjectId format.
- Loads
OAuthIntegrationby ID. - Verifies integration ownership (
integration.user === userId). - Delegates to
forward(provider, userId, request).
forward(...):
- Loads provider proxy config (
getProviderProxyConfig). - Enforces max body size for non-GET requests.
- Blocks sensitive provider paths using
blockedPaths. - Loads the user's provider integration.
- Runs provider-specific request validation via forwarder hook.
- Resolves OAuth token refresh config from provider registry.
- Gets a valid access token through
getValidAccessToken(...)(auto-refresh when close to expiry). - Resolves final upstream base URL/path.
- Builds outgoing headers:
Accept: application/json- provider auth header (for example, bearer token)
Content-Type: application/jsonfor non-GET with body- provider-specific header overrides via forwarder hook
- Sends upstream request with axios (30s timeout).
- Converts upstream
401/403intoNotAuthorizedError. - Returns upstream response with safe headers only (
content-type,x-request-id,retry-after).
Flow B: /proxy/encrypted/:integrationId/{*path} (encrypted token storage)
This is the key-split flow for integrations saved in encrypted mode.
Route layer (src/routes/proxy.ts)
- Reads
X-Encryption-Keyheader (required). - Parses it via
parseKeyFromString(...)into client key share bytes. - Validates
integrationIdand normalizes path/query/headers/body. - Calls
forwardWithEncryptedTokens(integrationId, userId, clientKeyShare, request). - For success: forwards status/data and safe headers.
- For errors:
- derives
statusCodefrom error object (default500) - returns
{ success: false, error } - if status is
401or403, also returns:authError: truereconnectRequired: true
- derives
Controller layer (src/controllers/proxy/forwardEncrypted.ts)
forwardWithEncryptedTokens(...):
- Validates ObjectId format.
- Loads integration and verifies ownership.
- Ensures integration uses
encryptionMode === 'encrypted'. - Loads provider config and applies body-size and blocked-path checks.
- Runs provider-specific validation hook.
- Resolves provider base URL and target URL.
- Executes request with one auth retry loop:
- fetches decrypted valid token via
getValidAccessTokenEncrypted(...) - on retry, passes
forceRefresh = true - builds provider headers and sends upstream request
- if upstream returns
401on first attempt, retries once after forced refresh
- fetches decrypted valid token via
- Returns upstream response (status, data, safe headers).
- Maps network/timeout failures to
BadRequestError.
Token lifecycle differences
-
Standard route (
/by-id):- uses backend token cache/token manager flow (
getValidAccessToken) - refreshes according to provider refresh configuration
- uses backend token cache/token manager flow (
-
Encrypted route (
/encrypted):- decrypts stored token material using client key share + server share
- refreshes and then re-encrypts/persists updated tokens through encrypted token service
- performs one forced-refresh retry after upstream
401
Security and safety controls
- JWT required for all proxy calls.
- Integration ownership enforced server-side.
- Per-user rate limiting applied before forwarding.
- Provider-specific blocked paths prevent unsafe endpoint forwarding.
- Request body size limits prevent large payload abuse.
- Only safe response headers are exposed back to clients.
- Encrypted route requires client key share header.
Typical request sequence (encrypted flow)
- Client sends request to
/proxy/encrypted/:integrationId/...with:- bearer token
X-Encryption-Key
- Route validates inputs and delegates to encrypted controller.
- Controller validates integration + ownership + mode.
- Token service decrypts and refreshes token if needed.
- Backend forwards request to provider API.
- If provider returns
401, backend refreshes token and retries once. - Backend returns provider response (or structured error with reconnect hints).
Files involved
src/routes/proxy.tssrc/controllers/proxy/forward.tssrc/controllers/proxy/forwardEncrypted.tssrc/services/oauth/providers/tokenManager.tssrc/services/oauth/encryptedTokenService.tssrc/services/proxy/providerConfig.tssrc/services/oauth/forwarder/*