Skip to content

Commit ce78c00

Browse files
authored
Merge pull request #88 from snyk-labs/develop
Feat/add oauth support
2 parents c98e2d8 + eba2a2d commit ce78c00

File tree

3 files changed

+142
-16
lines changed

3 files changed

+142
-16
lines changed

src/lib/request/request.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const getTopParentModuleName = (parent: NodeModule | null): string => {
4242
const makeSnykRequest = async (
4343
request: SnykRequest,
4444
snykToken = '',
45+
oauthBearerToken = '',
4546
apiUrl = DEFAULT_API,
4647
apiUrlREST = DEFAULT_REST_API,
4748
userAgentPrefix = '',
@@ -57,20 +58,31 @@ const makeSnykRequest = async (
5758
userAgentPrefix != '' && !userAgentPrefix.endsWith('/')
5859
? userAgentPrefix + '/'
5960
: userAgentPrefix;
61+
62+
// prioritize snykToken but use oauthBearerToken if snykToken isn't provided
63+
const authorizationToken = snykToken
64+
? `token ${snykToken}`
65+
: oauthBearerToken
66+
? `Bearer ${oauthBearerToken}`
67+
: '';
68+
6069
const requestHeaders: Record<string, any> = {
6170
'Content-Type':
6271
request.useRESTApi && request.body
6372
? 'application/vnd.api+json'
6473
: 'application/json',
65-
Authorization: 'token ' + snykToken,
74+
Authorization: authorizationToken,
6675
'User-Agent': `${topParentModuleName}${userAgentPrefixChecked}tech-services/snyk-request-manager/1.0`,
6776
};
6877
let apiClient;
6978
if (proxyUri) {
7079
apiClient = axios.create({
7180
baseURL: request.useRESTApi ? apiUrlREST : apiUrl,
7281
responseType: 'json',
73-
headers: { ...requestHeaders, ...request.headers },
82+
headers: {
83+
...requestHeaders,
84+
...request.headers,
85+
},
7486
transitional: {
7587
clarifyTimeoutError: true,
7688
},
@@ -81,7 +93,10 @@ const makeSnykRequest = async (
8193
apiClient = axios.create({
8294
baseURL: request.useRESTApi ? apiUrlREST : apiUrl,
8395
responseType: 'json',
84-
headers: { ...requestHeaders, ...request.headers },
96+
headers: {
97+
...requestHeaders,
98+
...request.headers,
99+
},
85100
transitional: {
86101
clarifyTimeoutError: true,
87102
},

src/lib/request/requestManager.ts

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ function getRESTAPI(endpoint: string): string {
4646
return new URL(`${apiData.protocol}//${apiData.host}/rest`).toString();
4747
}
4848

49+
function getOauthToken(): string {
50+
const oauthToken: string = process.env.SNYK_OAUTH_TOKEN || '';
51+
return oauthToken;
52+
}
53+
4954
const getConfig = (): { endpoint: string; token: string } => {
5055
const snykApiEndpoint: string =
5156
process.env.SNYK_API ||
@@ -69,6 +74,7 @@ class RequestsManager {
6974
_retryCounter: Map<string, number>;
7075
_MAX_RETRY_COUNT: number;
7176
_snykToken: string;
77+
_oauthBearerToken?: string; // Optional OAuth token
7278
_userAgentPrefix?: string;
7379

7480
//snykToken = '', burstSize = 10, period = 500, maxRetryCount = 5
@@ -82,6 +88,7 @@ class RequestsManager {
8288
this._events = {};
8389
this._retryCounter = new Map();
8490
this._MAX_RETRY_COUNT = params?.maxRetryCount || 5;
91+
this._oauthBearerToken = getOauthToken();
8592
this._snykToken = params?.snykToken ?? this._userConfig.token;
8693
this._apiUrl = this._userConfig.endpoint;
8794
this._apiUrlREST = getRESTAPI(this._userConfig.endpoint);
@@ -101,19 +108,41 @@ class RequestsManager {
101108
_makeRequest = async (request: QueuedRequest): Promise<void> => {
102109
const requestId = request.id;
103110
try {
104-
const response = await makeSnykRequest(
105-
request.snykRequest,
106-
this._snykToken,
107-
this._apiUrl,
108-
this._apiUrlREST,
109-
this._userAgentPrefix,
110-
);
111-
this._emit({
112-
eventType: eventType.data,
113-
channel: request.channel,
114-
requestId,
115-
data: response,
116-
});
111+
// Pass oauthBearerToken if available
112+
if (
113+
this._oauthBearerToken != null &&
114+
this._oauthBearerToken.trim() != ''
115+
) {
116+
const response = await makeSnykRequest(
117+
request.snykRequest,
118+
'',
119+
this._oauthBearerToken,
120+
this._apiUrl,
121+
this._apiUrlREST,
122+
this._userAgentPrefix,
123+
);
124+
this._emit({
125+
eventType: eventType.data,
126+
channel: request.channel,
127+
requestId,
128+
data: response,
129+
});
130+
} else {
131+
const response = await makeSnykRequest(
132+
request.snykRequest,
133+
this._snykToken,
134+
'',
135+
this._apiUrl,
136+
this._apiUrlREST,
137+
this._userAgentPrefix,
138+
);
139+
this._emit({
140+
eventType: eventType.data,
141+
channel: request.channel,
142+
requestId,
143+
data: response,
144+
});
145+
}
117146
} catch (err) {
118147
const overloadedError = requestsManagerError.requestsManagerErrorOverload(
119148
err,

test/lib/request/request.test.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,85 @@ describe('Test Snyk Utils error handling/classification', () => {
229229
}
230230
});
231231
});
232+
233+
describe('Test makeSnykRequest with oauthBearerToken', () => {
234+
beforeEach(() => {
235+
nock.cleanAll();
236+
});
237+
238+
afterEach(() => {
239+
nock.cleanAll();
240+
});
241+
242+
it('should set Bearer token in Authorization header when oauthBearerToken is provided for DEFAULT_API', async () => {
243+
const testToken = 'test-oauth-token';
244+
const request = {
245+
verb: 'GET',
246+
url: '/test-endpoint',
247+
};
248+
249+
const scope = nock('https://api.snyk.io/v1')
250+
.get('/test-endpoint')
251+
.matchHeader('Authorization', `Bearer ${testToken}`)
252+
.reply(200, { success: true });
253+
254+
await makeSnykRequest(request, '', testToken);
255+
256+
expect(scope.isDone()).toBe(true);
257+
});
258+
259+
it('should set Bearer token in Authorization header when oauthBearerToken is provided for DEFAULT_REST_API', async () => {
260+
const testToken = 'test-oauth-token';
261+
const request = {
262+
verb: 'GET',
263+
url: '/test-endpoint',
264+
useRESTApi: true,
265+
};
266+
267+
const scope = nock('https://api.snyk.io/rest/')
268+
.get('/test-endpoint')
269+
.matchHeader('Authorization', `Bearer ${testToken}`)
270+
.reply(200, { success: true });
271+
272+
await makeSnykRequest(request, '', testToken);
273+
274+
expect(scope.isDone()).toBe(true);
275+
});
276+
277+
it('should prioritize snykToken over oauthBearerToken when both are provided for DEFAULT_API', async () => {
278+
const snykToken = 'test-snyk-token';
279+
const oauthToken = 'test-oauth-token';
280+
const request = {
281+
verb: 'GET',
282+
url: '/test-endpoint',
283+
};
284+
285+
const scope = nock('https://api.snyk.io/v1')
286+
.get('/test-endpoint')
287+
.matchHeader('Authorization', `token ${snykToken}`)
288+
.reply(200, { success: true });
289+
290+
await makeSnykRequest(request, snykToken, oauthToken);
291+
292+
expect(scope.isDone()).toBe(true);
293+
});
294+
295+
it('should prioritize snykToken over oauthBearerToken when both are provided for DEFAULT_REST_API', async () => {
296+
const snykToken = 'test-snyk-token';
297+
const oauthToken = 'test-oauth-token';
298+
const request = {
299+
verb: 'GET',
300+
url: '/test-endpoint',
301+
useRESTApi: true,
302+
};
303+
304+
const scope = nock('https://api.snyk.io/rest/')
305+
.get('/test-endpoint')
306+
.matchHeader('Authorization', `token ${snykToken}`)
307+
.reply(200, { success: true });
308+
309+
await makeSnykRequest(request, snykToken, oauthToken);
310+
311+
expect(scope.isDone()).toBe(true);
312+
});
313+
});

0 commit comments

Comments
 (0)