Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions lib/core/concurrency-queue.js
Original file line number Diff line number Diff line change
Expand Up @@ -494,9 +494,11 @@ export function ConcurrencyQueue ({ axios, config, plugins = [] }) {
return Promise.reject(responseHandler(err))
}
} else if ((response.status === 401 && this.config.refreshToken)) {
// If error_code is 294 (2FA required), don't retry/refresh - pass through the error as-is
// Retry/refresh only for authentication-related 401s (e.g. token expiry). Do not retry
// when the API returns a specific error_code for non-auth issues (2FA, permission, etc.).
const apiErrorCode = response.data?.error_code
if (apiErrorCode === 294) {
const NON_AUTH_401_ERROR_CODES = new Set([294, 161]) // 294 = 2FA required, 161 = env/permission
if (apiErrorCode !== undefined && apiErrorCode !== null && NON_AUTH_401_ERROR_CODES.has(apiErrorCode)) {
const err = runPluginOnResponseForError(error)
return Promise.reject(responseHandler(err))
}
Expand Down
34 changes: 34 additions & 0 deletions test/unit/concurrency-Queue-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,40 @@ describe('Concurrency queue test', () => {
})
.catch(done)
})

it('should not refresh token when error_code is 161 (env/permission) with 401 status', done => {
let refreshTokenCallCount = 0
const refreshTokenStub = sinon.stub().callsFake(() => {
refreshTokenCallCount++
return Promise.resolve({ authorization: 'Bearer new_token' })
})

const axiosWithRefresh = client({
baseURL: `${host}:${port}`,
authorization: 'Bearer <token_value>',
refreshToken: refreshTokenStub
})

const mock = new MockAdapter(axiosWithRefresh.axiosInstance)
mock.onGet('/test161').reply(401, {
error_message: "Environment doesn't exists or insufficient permission to access it.",
error_code: 161
})

axiosWithRefresh.axiosInstance.get('/test161')
.then(() => {
done(new Error('Expected error was not thrown'))
})
.catch((error) => {
expect(refreshTokenCallCount).to.equal(0)
expect(refreshTokenStub.called).to.equal(false)
expect(error.response.status).to.equal(401)
expect(error.response.data.error_code).to.equal(161)
expect(error.response.data.error_message).to.include("Environment doesn't exists or insufficient permission")
done()
})
.catch(done)
})
})

function makeConcurrencyQueue (config) {
Expand Down
Loading