Skip to content
This repository was archived by the owner on Nov 20, 2025. It is now read-only.

Commit c0181c5

Browse files
fix: process undefined values before creating URLSearchParams (#2029)
1 parent ebb2bc0 commit c0181c5

5 files changed

Lines changed: 86 additions & 12 deletions

File tree

src/auth/oauth2client.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import * as querystring from 'querystring';
2323
import * as stream from 'stream';
2424
import * as formatEcdsa from 'ecdsa-sig-formatter';
2525

26+
import {removeUndefinedValuesInObject} from '../util';
2627
import {createCrypto, JwkCertificate, hasBrowserCrypto} from '../crypto/crypto';
2728

2829
import {
@@ -754,7 +755,7 @@ export class OAuth2Client extends AuthClient {
754755
...OAuth2Client.RETRY_CONFIG,
755756
method: 'POST',
756757
url,
757-
data: new URLSearchParams(values as {}),
758+
data: new URLSearchParams(removeUndefinedValuesInObject(values) as {}),
758759
headers,
759760
};
760761
AuthClient.setMethodName(opts, 'getTokenAsync');
@@ -820,7 +821,7 @@ export class OAuth2Client extends AuthClient {
820821
...OAuth2Client.RETRY_CONFIG,
821822
method: 'POST',
822823
url,
823-
data: new URLSearchParams(data),
824+
data: new URLSearchParams(removeUndefinedValuesInObject(data)),
824825
};
825826
AuthClient.setMethodName(opts, 'refreshTokenNoCache');
826827

src/auth/stscredentials.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import {
2222
getErrorFromOAuthErrorResponse,
2323
} from './oauth2common';
2424

25+
import {removeUndefinedValuesInObject} from '../util';
26+
2527
/**
2628
* Defines the interface needed to initialize an StsCredentials instance.
2729
* The interface does not directly map to the spec and instead is converted
@@ -203,20 +205,12 @@ export class StsCredentials extends OAuthClientAuthHandler {
203205
options: options && JSON.stringify(options),
204206
};
205207

206-
// Keep defined fields.
207-
const payload: Record<string, string> = {};
208-
Object.entries(values).forEach(([key, value]) => {
209-
if (value !== undefined) {
210-
payload[key] = value;
211-
}
212-
});
213-
214208
const opts: GaxiosOptions = {
215209
...StsCredentials.RETRY_CONFIG,
216210
url: this.#tokenExchangeEndpoint.toString(),
217211
method: 'POST',
218212
headers,
219-
data: new URLSearchParams(payload),
213+
data: new URLSearchParams(removeUndefinedValuesInObject(values)),
220214
};
221215
AuthClient.setMethodName(opts, 'exchangeToken');
222216

src/util.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,15 @@ export class LRUCache<T> {
239239
}
240240
}
241241
}
242+
243+
// Given and object remove fields where value is undefined.
244+
export function removeUndefinedValuesInObject(object: {[key: string]: any}): {
245+
[key: string]: any;
246+
} {
247+
Object.entries(object).forEach(([key, value]) => {
248+
if (value === undefined || value === 'undefined') {
249+
delete object[key];
250+
}
251+
});
252+
return object;
253+
}

test/test.oauth2.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,6 +1370,52 @@ describe('oauth2', () => {
13701370
assert.strictEqual(params.get('code_verifier'), 'its_verified');
13711371
});
13721372

1373+
it('getToken should ignore undefined code verifier', async () => {
1374+
const scope = nock(baseUrl, {
1375+
reqheaders: {
1376+
'content-type': 'application/x-www-form-urlencoded;charset=UTF-8',
1377+
},
1378+
})
1379+
.post('/token')
1380+
.reply(200, {
1381+
access_token: 'abc',
1382+
refresh_token: '123',
1383+
expires_in: 10,
1384+
});
1385+
const res = await client.getToken({
1386+
code: 'code here',
1387+
codeVerifier: undefined,
1388+
});
1389+
scope.done();
1390+
assert(res.res);
1391+
1392+
const params = new URLSearchParams(res.res.config.data || '');
1393+
assert.strictEqual(params.get('code_verifier'), null);
1394+
});
1395+
1396+
it('getToken should ignore undefined string code verifier', async () => {
1397+
const scope = nock(baseUrl, {
1398+
reqheaders: {
1399+
'content-type': 'application/x-www-form-urlencoded;charset=UTF-8',
1400+
},
1401+
})
1402+
.post('/token')
1403+
.reply(200, {
1404+
access_token: 'abc',
1405+
refresh_token: '123',
1406+
expires_in: 10,
1407+
});
1408+
const res = await client.getToken({
1409+
code: 'code here',
1410+
codeVerifier: 'undefined',
1411+
});
1412+
scope.done();
1413+
assert(res.res);
1414+
1415+
const params = new URLSearchParams(res.res.config.data || '');
1416+
assert.strictEqual(params.get('code_verifier'), null);
1417+
});
1418+
13731419
it('getToken should set redirect_uri if not provided in options', async () => {
13741420
const scope = nock(baseUrl, {
13751421
reqheaders: {

test/test.util.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import {strict as assert} from 'assert';
1616
import * as sinon from 'sinon';
1717

18-
import {LRUCache} from '../src/util';
18+
import {LRUCache, removeUndefinedValuesInObject} from '../src/util';
1919

2020
describe('util', () => {
2121
let sandbox: sinon.SinonSandbox;
@@ -81,3 +81,24 @@ describe('util', () => {
8181
});
8282
});
8383
});
84+
85+
describe('util removeUndefinedValuesInObject', () => {
86+
it('remove undefined type values in object', () => {
87+
const object: {[key: string]: any} = {
88+
undefined: undefined,
89+
number: 1,
90+
};
91+
assert.deepEqual(removeUndefinedValuesInObject(object), {
92+
number: 1,
93+
});
94+
});
95+
it('remove undefined string values in object', () => {
96+
const object: {[key: string]: any} = {
97+
undefined: 'undefined',
98+
number: 1,
99+
};
100+
assert.deepEqual(removeUndefinedValuesInObject(object), {
101+
number: 1,
102+
});
103+
});
104+
});

0 commit comments

Comments
 (0)