fix(auth-oauth1): sign with the token secret when no access token is set (#611)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Gregory Schier
2026-08-27 15:27:40 -07:00
committed by GitHub
co-authored by Claude Fable 5
parent 0aae516f3a
commit 50cccf1d25
2 changed files with 20 additions and 1 deletions
+5 -1
View File
@@ -161,7 +161,7 @@ export const plugin: PluginDefinition = {
if (values.timestamp) requestData.data.oauth_timestamp = String(values.timestamp); if (values.timestamp) requestData.data.oauth_timestamp = String(values.timestamp);
if (values.verifier) requestData.data.oauth_verifier = String(values.verifier); if (values.verifier) requestData.data.oauth_verifier = String(values.verifier);
let token: OAuth.Token | { key: string } | undefined; let token: OAuth.Token | { key: string } | { secret: string } | undefined;
if (pkSigs.includes(signatureMethod)) { if (pkSigs.includes(signatureMethod)) {
token = { token = {
@@ -172,6 +172,10 @@ export const plugin: PluginDefinition = {
token = { key: String(values.tokenKey), secret: String(values.tokenSecret) }; token = { key: String(values.tokenKey), secret: String(values.tokenSecret) };
} else if (values.tokenKey) { } else if (values.tokenKey) {
token = { key: String(values.tokenKey) }; token = { key: String(values.tokenKey) };
} else if (values.tokenSecret) {
// The secret still joins the signing key without an access token;
// leaving `key` out keeps oauth_token out of the header entirely
token = { secret: String(values.tokenSecret) };
} }
const authParams = oauth.authorize(requestData, token as OAuth.Token | undefined); const authParams = oauth.authorize(requestData, token as OAuth.Token | undefined);
@@ -34,6 +34,21 @@ describe("PLAINTEXT signature", () => {
expect(sign(base)).toBe("cs&"); expect(sign(base)).toBe("cs&");
}); });
test("includes the token secret without an access token, omitting oauth_token", () => {
const result = plugin.authentication!.onApply!(
{} as never,
{
values: { ...base, tokenSecret: "ts" },
method: "GET",
url: "https://api.example.com/resource",
} as never,
) as { setHeaders: { name: string; value: string }[] };
const header = result.setHeaders[0]!.value;
const match = header.match(/oauth_signature="([^"]*)"/);
expect(decodeURIComponent(match![1]!)).toBe("cs&ts");
expect(header).not.toContain("oauth_token=");
});
test("percent-encodes reserved characters in the secrets", () => { test("percent-encodes reserved characters in the secrets", () => {
expect(sign({ ...base, consumerSecret: "c s", tokenKey: "tk", tokenSecret: "t&s" })).toBe( expect(sign({ ...base, consumerSecret: "c s", tokenKey: "tk", tokenSecret: "t&s" })).toBe(
"c%20s&t%26s", "c%20s&t%26s",