Skip to content

Commit dedbd32

Browse files
author
BitGo Agent
committed
fix(sdk-api): guard v1 auth path against undefined accessToken in testnet
When BitGoAPI is constructed with accessToken: undefined (e.g. TESTNET_ACCESS_TOKEN env var not set) and a request sets forceV1Auth = true, the v1 auth condition previously evaluated as: (undefined && ...) || true → true causing the request to set Authorization: 'Bearer undefined', which the server rejects with an 'undefined access token' error. Fix: require this._token to be truthy before entering the v1 path, so forceV1Auth cannot bypass the token guard. Unauthenticated requests now proceed without an Authorization header (the existing behaviour for requests with no token) rather than sending a literally-undefined bearer value. Ticket: WCI-1213 Session-Id: 90ff7750-f83b-4600-a00a-fb07afa1cb4a Task-Id: a55a5860-e651-49e1-9ea1-0867be6b19d3
1 parent f7b8d3a commit dedbd32

2 files changed

Lines changed: 43 additions & 1 deletion

File tree

modules/sdk-api/src/bitgoAPI.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ export class BitGoAPI implements BitGoBase {
645645
req.isV2Authenticated = true;
646646
req.authenticationToken = this._token ?? (strategyAuthenticated ? 'strategy-authenticated' : undefined);
647647
// some of the older tokens appear to be only 40 characters long
648-
if ((this._token && this._token.length !== 67 && this._token.indexOf('v2x') !== 0) || req.forceV1Auth) {
648+
if (this._token && ((this._token.length !== 67 && this._token.indexOf('v2x') !== 0) || req.forceV1Auth)) {
649649
// use the old method
650650
req.isV2Authenticated = false;
651651

modules/sdk-api/test/unit/bitgoAPI.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,3 +1192,45 @@ describe('wallets() v1 facade', function () {
11921192
wallets.resendShareInvite.should.be.a.Function();
11931193
});
11941194
});
1195+
1196+
describe('undefined accessToken in testnet (WCI-1213)', function () {
1197+
const ROOT = 'https://app.bitgo-test.com';
1198+
1199+
afterEach(function () {
1200+
nock.cleanAll();
1201+
});
1202+
1203+
it('does not send "Bearer undefined" when accessToken is undefined (no forceV1Auth)', async function () {
1204+
const bitgo = new BitGoAPI({ env: 'test', accessToken: undefined });
1205+
1206+
let receivedAuthHeader: string | null = null;
1207+
nock(ROOT)
1208+
.post('/api/auth/v1/session')
1209+
.reply(function (uri, body) {
1210+
receivedAuthHeader = this.req.headers['authorization']?.[0] ?? null;
1211+
return [200, { user: { username: 'test@example.com' }, access_token: 'v2xtoken' }];
1212+
});
1213+
1214+
await bitgo.authenticate({ username: 'test@example.com', password: 'pw', otp: '000000' });
1215+
1216+
// With no token set, the v1 path must not be entered — so no 'Bearer undefined'
1217+
assert.notStrictEqual(receivedAuthHeader, 'Bearer undefined');
1218+
});
1219+
1220+
it('does not send "Bearer undefined" when accessToken is undefined and forceV1Auth is set', async function () {
1221+
const bitgo = new BitGoAPI({ env: 'test', accessToken: undefined });
1222+
1223+
let receivedAuthHeader: string | null = null;
1224+
nock(ROOT)
1225+
.post('/api/auth/v1/session')
1226+
.reply(function (uri, body) {
1227+
receivedAuthHeader = this.req.headers['authorization']?.[0] ?? null;
1228+
return [200, { user: { username: 'test@example.com' }, access_token: 'v2xtoken' }];
1229+
});
1230+
1231+
await bitgo.authenticate({ username: 'test@example.com', password: 'pw', otp: '000000', forceV1Auth: true });
1232+
1233+
// forceV1Auth must not bypass the token guard — header must not be 'Bearer undefined'
1234+
assert.notStrictEqual(receivedAuthHeader, 'Bearer undefined');
1235+
});
1236+
});

0 commit comments

Comments
 (0)