feat: adds support for jwt auth to provider-proxy#1963
Conversation
WalkthroughRefactors provider authentication across HTTP and WebSocket paths by introducing a unified auth model (mtls/jwt) and network field in schema, replacing legacy certificate fields. Updates ProviderProxy connection options and agent management, adjusts route and WS flows, revises imports/paths, augments tests for mtls/jwt, and tweaks build/dependencies. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Client
participant Route as HTTP Route
participant Schema as addProviderAuthValidation
participant Proxy as ProviderProxy
participant Provider as Provider API
Client->>Route: POST /proxy { method, url, body, network, providerAddress, auth? }
Route->>Schema: validate payload (auth mtls/jwt or legacy)
Schema-->>Route: normalized { ... , auth?, network }
Route->>Proxy: connect({ method, auth, body, headers, network, timeout, providerAddress })
Proxy->>Proxy: build requestOptions + agentCacheKey
alt auth.type == "mtls"
Proxy->>Proxy: getHttpsAgent(cert,key,servername="")
else auth.type == "jwt"
Proxy->>Proxy: set Authorization: Bearer <token>
Proxy->>Proxy: getHttpsAgent(default)
end
Proxy->>Provider: HTTPS request
Provider-->>Proxy: Response (socket, headers)
alt socket.authorized or cert validated
Proxy-->>Route: stream response
else invalid cert
Proxy->>Proxy: drop cached agent
Proxy-->>Route: error
end
Route-->>Client: response / error
sequenceDiagram
autonumber
actor Client
participant WSS as WebsocketServer
participant Conn as connectWebSocket
participant Provider as Provider WS
Client->>WSS: message { url, network, providerAddress, auth?, ... }
WSS->>WSS: validate via MESSAGE_SCHEMA (addProviderAuthValidation)
WSS->>Conn: connect(url, { network, auth })
alt auth.type == "mtls"
Conn->>Provider: WS with TLS cert/key
else auth.type == "jwt"
Conn->>Provider: WS with Authorization: Bearer <token>
else no auth
Conn->>Provider: WS default
end
Conn-->>WSS: providerSocket (verification=in-progress)
WSS->>WSS: verify (mtls cert or token flow)
alt verified
WSS->>WSS: mark verification=finished
WSS-->>Client: "verified"
WSS-->>Client: proxy stream
else failed
WSS->>WSS: mark verification=failed
WSS-->>Client: error
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (11)
🚧 Files skipped from review as they are similar to previous changes (5)
🧰 Additional context used📓 Path-based instructions (3)**/*.{ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/general.mdc)
Files:
**/*.{js,ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/general.mdc)
Files:
**/*.spec.{ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)
Files:
🧠 Learnings (1)📚 Learning: 2025-07-21T08:24:27.953ZApplied to files:
🧬 Code graph analysis (6)apps/provider-proxy/src/utils/schema.ts (3)
apps/provider-proxy/src/routes/proxyProviderRequest.ts (1)
apps/provider-proxy/src/services/WebsocketServer.ts (4)
apps/provider-proxy/src/services/ProviderProxy.ts (1)
apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (4)
apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (4)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
🔇 Additional comments (30)
Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1963 +/- ##
==========================================
+ Coverage 45.06% 45.13% +0.06%
==========================================
Files 998 998
Lines 28170 28210 +40
Branches 7372 7382 +10
==========================================
+ Hits 12695 12732 +37
- Misses 14350 14372 +22
+ Partials 1125 1106 -19
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/provider-proxy/src/routes/proxyProviderRequest.ts (1)
31-38: OpenAPI 400 response schema mismatch (JSON vs text).The route returns JSON for certain 400 cases (SSL/client cert invalid), but the OpenAPI spec declares only text/plain for 400. This breaks clients relying on the spec.
Apply this diff to add "application/json" to 400 responses:
responses: { - content: { - "text/plain": { - schema: z.string() - } - }, + content: { + "text/plain": { schema: z.string() }, + "application/json": { + schema: z.object({ + error: z.object({ + code: z.string(), + issues: z.array( + z.object({ + path: z.array(z.union([z.string(), z.number()])), + params: z.record(z.unknown()).optional() + }) + ) + }) + }) + } + }, description: "Returned if it's not possible to establish secure connection with proxied host" },Alternatively, return text consistently for 400 or wrap all 400s as JSON and reflect that in the spec.
Also applies to: 117-132
apps/provider-proxy/src/services/WebsocketServer.ts (1)
237-237: Remove any and correctly build BufferAvoid any; parse numbers explicitly to ensure correct byte values.
- const data = Buffer.from(message.data.split(",") as any); + const data = Buffer.from(message.data.split(",").map(n => Number.parseInt(n, 10)));
🧹 Nitpick comments (7)
apps/provider-proxy/package.json (1)
9-9: Pin @akashnetwork/jwt, and verify TypeScript version.
- Avoid using "*" for dependencies. Pin "@akashnetwork/jwt" to a known compatible version/range to ensure reproducible builds.
- Confirm that the specified TypeScript version "~5.8.2" exists in your registry. If not, adjust to an available version.
Also, confirm the intent of "--packages=external": the runtime must have deps available in node_modules for prod execution (which seems fine with "start" invoking node on dist).
If helpful, I can scan the repo and PR history to propose an exact version for @akashnetwork/jwt that matches current usage/tests.
Also applies to: 25-25, 44-44
apps/provider-proxy/src/services/CertificateValidator/CertificateValidator.ts (3)
19-20: Typo in instrumentation type name (constructor parameter).Rename "CertificateValidatorIntrumentation" to "CertificateValidatorInstrumentation" for correctness and consistency.
Apply this diff:
constructor( private readonly now: () => number, private readonly providerService: ProviderService, - private readonly instrumentation?: CertificateValidatorIntrumentation + private readonly instrumentation?: CertificateValidatorInstrumentation ) {}
71-82: Fix misspelled interface name; keep a back-compat alias.The interface is misspelled ("Intrumentation"). Introduce the correctly spelled name and alias the old one.
Apply this diff:
-export interface CertificateValidatorIntrumentation { +export interface CertificateValidatorInstrumentation { onValidationSuccess?(certificate: X509Certificate, network: SupportedChainNetworks, providerAddress: string, now: number): void; onInvalidAttrs?( certificate: X509Certificate, network: SupportedChainNetworks, providerAddress: string, now: number, validationResult: CertValidationResultError ): void; onUnknownCert?(certificate: X509Certificate, network: SupportedChainNetworks, providerAddress: string): void; onInvalidFingerprint?(certificate: X509Certificate, network: SupportedChainNetworks, providerAddress: string, providerCertificate: X509Certificate): void; } + +// Backward compatibility alias (to avoid breaking imports) +export type CertificateValidatorIntrumentation = CertificateValidatorInstrumentation;
84-99: Align factory’s return type with corrected interface.Update the return type of the instrumentation factory to the corrected interface name.
Apply this diff:
-export const createCertificateValidatorInstrumentation = (logger: LoggerService): CertificateValidatorIntrumentation => ({ +export const createCertificateValidatorInstrumentation = (logger: LoggerService): CertificateValidatorInstrumentation => ({ onValidationSuccess(certificate, network, providerAddress, now) { logger.info(`Successfully validated ${certificate.serialNumber} in ${network} for "${providerAddress}" at ${now}`); }, onInvalidAttrs(certificate, network, providerAddress, now, result) { logger.warn(`Certificate ${certificate.serialNumber} is invalid in ${network} for "${providerAddress}" because ${result.code} at ${now}`); },apps/provider-proxy/src/services/ProviderProxy.ts (2)
18-20: Agents cache can grow very largemax: 1_000_000 without TTL risks memory pressure. Consider a tighter max and/or TTL based on expected concurrency and session reuse.
61-61: Redundant checksnetwork and providerAddress are required; the didHandshake check alone is sufficient.
apps/provider-proxy/src/services/WebsocketServer.ts (1)
251-256: Minor: log message mentions certificate but JWT path also existsConsider generic wording like “identity verification” to cover both CA and custom cert validation.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (11)
apps/provider-proxy/package.json(3 hunks)apps/provider-proxy/src/container.ts(1 hunks)apps/provider-proxy/src/routes/proxyProviderRequest.ts(4 hunks)apps/provider-proxy/src/services/CertificateValidator/CertificateValidator.spec.ts(1 hunks)apps/provider-proxy/src/services/CertificateValidator/CertificateValidator.ts(1 hunks)apps/provider-proxy/src/services/ProviderProxy.ts(6 hunks)apps/provider-proxy/src/services/WebsocketServer.ts(13 hunks)apps/provider-proxy/src/utils/schema.ts(2 hunks)apps/provider-proxy/test/functional/provider-proxy-http.spec.ts(4 hunks)apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts(3 hunks)apps/provider-proxy/test/setup/providerServer.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/general.mdc)
Never use type any or cast to type any. Always define the proper TypeScript types.
Files:
apps/provider-proxy/test/setup/providerServer.tsapps/provider-proxy/src/container.tsapps/provider-proxy/test/functional/provider-proxy-http.spec.tsapps/provider-proxy/src/utils/schema.tsapps/provider-proxy/src/services/CertificateValidator/CertificateValidator.spec.tsapps/provider-proxy/src/services/ProviderProxy.tsapps/provider-proxy/src/services/WebsocketServer.tsapps/provider-proxy/test/functional/provider-proxy-ws.spec.tsapps/provider-proxy/src/services/CertificateValidator/CertificateValidator.tsapps/provider-proxy/src/routes/proxyProviderRequest.ts
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/general.mdc)
**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code
Files:
apps/provider-proxy/test/setup/providerServer.tsapps/provider-proxy/src/container.tsapps/provider-proxy/test/functional/provider-proxy-http.spec.tsapps/provider-proxy/src/utils/schema.tsapps/provider-proxy/src/services/CertificateValidator/CertificateValidator.spec.tsapps/provider-proxy/src/services/ProviderProxy.tsapps/provider-proxy/src/services/WebsocketServer.tsapps/provider-proxy/test/functional/provider-proxy-ws.spec.tsapps/provider-proxy/src/services/CertificateValidator/CertificateValidator.tsapps/provider-proxy/src/routes/proxyProviderRequest.ts
**/*.spec.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)
Don't use
jest.mock()to mock dependencies in test files. Instead, usejest-mock-extendedto create mocks and pass mocks as dependencies to the service under test.
**/*.spec.{ts,tsx}: Usesetupfunction instead ofbeforeEachin test files
setupfunction must be at the bottom of the rootdescribeblock in test files
setupfunction creates an object under test and returns it
setupfunction should accept a single parameter with inline type definition
Don't use shared state insetupfunction
Don't specify return type ofsetupfunction
Files:
apps/provider-proxy/test/functional/provider-proxy-http.spec.tsapps/provider-proxy/src/services/CertificateValidator/CertificateValidator.spec.tsapps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
🧬 Code graph analysis (7)
apps/provider-proxy/test/setup/providerServer.ts (1)
apps/provider-proxy/test/seeders/createX509CertPair.ts (1)
CertPair(28-31)
apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (4)
apps/provider-proxy/test/setup/chainApiServer.ts (2)
generateBech32(61-63)startChainApiServer(13-50)apps/provider-proxy/test/seeders/createX509CertPair.ts (1)
createX509CertPair(4-26)apps/provider-proxy/test/setup/providerServer.ts (1)
startProviderServer(14-71)apps/provider-proxy/test/setup/proxyServer.ts (1)
request(15-27)
apps/provider-proxy/src/utils/schema.ts (3)
packages/net/src/index.ts (1)
netConfig(3-3)apps/provider-proxy/src/utils/isValidBech32.ts (1)
isValidBech32Address(3-10)apps/provider-proxy/src/utils/validateClientCertificateAttrs.ts (1)
validateClientCertificateAttrs(6-11)
apps/provider-proxy/src/services/ProviderProxy.ts (1)
apps/provider-proxy/src/utils/schema.ts (1)
providerRequestSchema(9-32)
apps/provider-proxy/src/services/WebsocketServer.ts (4)
apps/provider-proxy/src/utils/schema.ts (2)
addProviderAuthValidation(41-82)providerRequestSchema(9-32)apps/provider-proxy/src/utils/telemetry.ts (1)
propagateTracingContext(9-12)apps/provider-proxy/src/services/WebsocketStats.ts (1)
ClientWebSocketStats(22-78)packages/net/src/NetConfig/NetConfig.ts (1)
SupportedChainNetworks(3-3)
apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (4)
apps/provider-proxy/test/setup/proxyServer.ts (1)
startServer(6-9)apps/provider-proxy/test/setup/chainApiServer.ts (2)
generateBech32(61-63)startChainApiServer(13-50)apps/provider-proxy/test/seeders/createX509CertPair.ts (1)
createX509CertPair(4-26)apps/provider-proxy/test/setup/providerServer.ts (1)
startProviderServer(14-71)
apps/provider-proxy/src/routes/proxyProviderRequest.ts (1)
apps/provider-proxy/src/utils/schema.ts (2)
addProviderAuthValidation(41-82)providerRequestSchema(9-32)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
- GitHub Check: validate (apps/api) / validate-unsafe
- GitHub Check: validate (apps/deploy-web) / validate-unsafe
- GitHub Check: test-build
- GitHub Check: test-build
- GitHub Check: validate / validate-app
- GitHub Check: validate / validate-app
- GitHub Check: test-build
- GitHub Check: validate / validate-app
- GitHub Check: test-build
- GitHub Check: validate / validate-app
- GitHub Check: test-build
- GitHub Check: test-build
- GitHub Check: validate / validate-app
- GitHub Check: test-build
🔇 Additional comments (10)
apps/provider-proxy/src/container.ts (1)
6-6: LGTM: import path realignment.Importing CertificateValidator from its dedicated directory improves cohesion without behavior change.
apps/provider-proxy/src/services/CertificateValidator/CertificateValidator.spec.ts (1)
4-8: LGTM: import adjustments.Path changes to local module and test seeders look correct; tests remain valid and isolated.
apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (3)
213-214: LGTM: error path updated to auth.certPem.Matches the new provider auth schema and validation.
Also applies to: 493-494
596-664: LGTM: MTLS flow test.Solid positive and negative-path coverage for MTLS auth.
666-741: LGTM: JWT flow test.JWT creation and validation checks are clear; invalid token path asserts expected error shape.
apps/provider-proxy/test/setup/providerServer.ts (2)
22-25: LGTM: optional client cert support for tests.Enabling requestCert without rejecting unauthorized clients is appropriate for these functional tests.
79-85: LGTM: WS onConnection signature extended.Passing the IncomingMessage to handlers makes MTLS/JWT verification straightforward in tests.
apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (2)
230-292: LGTM: MTLS flow over WebSocket.Covers both success and validation error. Good use of TLSSocket to assert client cert presence.
383-384: LGTM: 'network' field normalization in ourMessage.Maintains compatibility with older call sites while emitting the new 'network' field.
apps/provider-proxy/src/utils/schema.ts (1)
84-90: JWT validation here does not verify signature — confirm intended scopeThis only decodes and validates payload shape/claims. If signature verification is expected here, a signer/verification key must be configured; otherwise, leave as-is and consider renaming the error to “invalid JWT payload”.
904153d to
4fe95b0
Compare
Why
#1952
Summary by CodeRabbit
New Features
Deprecations
Tests
Chores