Skip to content

OAuth1 proxy signs spaces in object query params as literal plus characters #7098

Description

@xuanyuzhou98

Description

OAuth1 proxy requests can receive an invalid signature when an object query parameter contains a space. The object and pre-serialized forms of the same parameters produce different authentication results.

This was reproduced with an X Ads OAuth1 integration through Nango Cloud. No credentials or account identifiers are included below.

Minimal reproduction

Using @nangohq/node 0.70.5:

await nango.proxy({
  method: "GET",
  endpoint: "/resource",
  providerConfigKey: "oauth1-integration",
  connectionId: "connection-id",
  params: { q: "ai music" }
});

The object form constructs a query containing q=ai+music. With X Ads this returned HTTP 401 UNAUTHORIZED_ACCESS.

Passing the same value as a pre-serialized query changes the authentication outcome:

await nango.proxy({
  method: "GET",
  endpoint: "/resource",
  providerConfigKey: "oauth1-integration",
  connectionId: "connection-id",
  params: "q=ai%20music"
});

This request passed OAuth authentication and reached the upstream endpoint handler. For the tested X Ads read endpoint, the response was its endpoint-level HTTP 503 SERVICE_UNAVAILABLE, matching a request signed directly with the same credentials. Values without spaces did not produce the 401.

Suspected cause

Current master still appears affected at commit 2e17e5dca772345a21905817537df01c82fccfa7:

  1. buildProxyURL uses URLSearchParams.set and then URL.toString, which serializes spaces as +.
  2. The OAuth1 request path passes that URL to oauth-1.0a.
  3. oauth-1.0a parses the query with decodeURIComponent without converting form-encoded + to a space. It consequently signs the value as a literal plus (%2B). The OAuth provider parses the query value as a space and calculates %20, so the signature bases differ.

Expected behavior

Object query parameters and equivalent pre-serialized query parameters should produce the same valid OAuth1 signature.

Suggested fix and regression coverage

Normalize object query parameters to RFC 3986 encoding before both the outbound request and OAuth1 signing, or ensure + is decoded as a space before building the OAuth1 parameter string.

A regression test with { q: "ai music" } should verify that:

  • the outbound query and OAuth1 signature use the same decoded value;
  • a literal plus remains distinguishable from a space;
  • object and pre-serialized %20 parameter forms produce equivalent OAuth1 signatures.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions