Skip to content

Commit b0d4c00

Browse files
committed
accept access_token
1 parent a9b63ac commit b0d4c00

File tree

4 files changed

+45
-32
lines changed

4 files changed

+45
-32
lines changed

lib/base_service.ts

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export interface UserOptions {
3838
use_unauthenticated?: boolean;
3939
headers?: HeaderOptions;
4040
token?: string;
41+
access_token?: string;
4142
}
4243

4344
export interface BaseServiceOptions extends UserOptions {
@@ -52,18 +53,19 @@ export interface Credentials {
5253
password: string;
5354
api_key: string;
5455
url: string;
56+
access_token: string;
5557
}
5658

5759
function hasCredentials(obj: any): boolean {
58-
return obj && ((obj.username && obj.password) || obj.api_key);
60+
return obj && ((obj.username && obj.password) || obj.api_key || obj.access_token);
5961
}
6062

6163
function hasBasicCredentials(obj: any): boolean {
6264
return obj && obj.username && obj.password;
6365
}
6466

65-
function acceptsApiKey(name: string): boolean {
66-
return name === 'visual_recognition';
67+
function hasAccessToken(obj: any): boolean {
68+
return obj && obj.access_token;
6769
}
6870

6971
export class BaseService {
@@ -132,9 +134,26 @@ export class BaseService {
132134
if (this._options.url) {
133135
_credentials.url = this._options.url;
134136
}
137+
if (this._options.access_token) {
138+
_credentials.access_token = this._options.access_token;
139+
}
135140
return _credentials;
136141
}
137142

143+
/**
144+
* Set an IAM access token to authenticate the service with
145+
* The SDK will assume this token is valid and that this method
146+
* will be used to set a new token upon expiration.
147+
*
148+
* @param {string} accessToken - Valid IAM access token
149+
* @returns {void}
150+
*/
151+
public setAccessToken(accessToken: string) {
152+
this._options.access_token = accessToken;
153+
this._options.headers = this._options.headers || {};
154+
this._options.headers.Authorization = `Bearer ${accessToken}`;
155+
}
156+
138157
/**
139158
* @private
140159
* @param {UserOptions} options
@@ -162,24 +181,12 @@ export class BaseService {
162181
_options
163182
);
164183
if (!_options.use_unauthenticated) {
165-
if (!hasCredentials(_options) && acceptsApiKey(this.name)) {
166-
throw new Error(
167-
`Argument error: api_key or username/password are required for ${this.name
168-
.toUpperCase()
169-
.replace(
170-
/_/g,
171-
' '
172-
)} ${this.serviceVersion.toUpperCase()} unless use_unauthenticated is set`
173-
);
174-
} else if (!hasCredentials(_options)) {
175-
throw new Error(
176-
`Argument error: username and password are required for ${this.name
177-
.toUpperCase()
178-
.replace(
179-
/_/g,
180-
' '
181-
)} ${this.serviceVersion.toUpperCase()} unless use_unauthenticated is set`
182-
);
184+
if (!hasCredentials(_options)) {
185+
const errorMessage = 'Insufficient credentials provided in ' +
186+
'constructor argument. Refer to the documentation for the ' +
187+
'required parameters. Common examples are username/password, ' +
188+
'api_key, and access_token.';
189+
throw new Error(errorMessage);
183190
}
184191
if (hasBasicCredentials(_options)) {
185192
// Calculate and add Authorization header to base options
@@ -188,6 +195,9 @@ export class BaseService {
188195
).toString('base64');
189196
const authHeader = { Authorization: `Basic ${encodedCredentials}` };
190197
_options.headers = extend(authHeader, _options.headers);
198+
} else if (hasAccessToken(_options)) {
199+
const authHeader = { Authorization: `Bearer ${_options.access_token}` };
200+
_options.headers = extend(authHeader, _options.headers);
191201
} else {
192202
_options.qs = extend({ api_key: _options.api_key }, _options.qs);
193203
}
@@ -221,12 +231,14 @@ export class BaseService {
221231
const _password: string = process.env[`${_name}_PASSWORD`] || process.env[`${_nameWithUnderscore}_PASSWORD`];
222232
const _apiKey: string = process.env[`${_name}_API_KEY`] || process.env[`${_nameWithUnderscore}_API_KEY`];
223233
const _url: string = process.env[`${_name}_URL`] || process.env[`${_nameWithUnderscore}_URL`];
234+
const _accessToken: string = process.env[`${_name}_ACCESS_TOKEN`] || process.env[`${_nameWithUnderscore}_ACCESS_TOKEN`];
224235

225236
return {
226237
username: _username,
227238
password: _password,
228239
api_key: _apiKey,
229-
url: _url
240+
url: _url,
241+
access_token: _accessToken
230242
};
231243
}
232244
/**

lib/requestwrapper.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,19 +110,20 @@ export function formatErrorIfExists(cb: Function): request.RequestCallback {
110110
});
111111
body = null;
112112
}
113-
114113
// If we still don't have an error and there was an error...
115114
if (!error && (response.statusCode < 200 || response.statusCode >= 300)) {
116115
// The JSON stringify for the error below is for the Dialog service
117116
// It stringifies "[object Object]" into the correct error (PR #445)
118117
error = new Error(typeof body === 'object' ? JSON.stringify(body) : body);
119118
error.code = response.statusCode;
120-
if (error.code === 401 || error.code === 403) {
121-
error.body = error.message;
122-
error.message = 'Unauthorized: Access is denied due to invalid credentials.';
123-
}
124119
body = null;
125120
}
121+
122+
// ensure a more descriptive error message
123+
if (error && (error.code === 401 || error.code === 403)) {
124+
error.body = error.message;
125+
error.message = 'Unauthorized: Access is denied due to invalid credentials.';
126+
}
126127
if (error && response && response.headers) {
127128
error[globalTransactionId] = response.headers[globalTransactionId];
128129
}

test/unit/test.visual_recognition.v3.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,15 +105,15 @@ describe('visual_recognition', function() {
105105
});
106106

107107
it('should throw when no/insufficient credentials are provided', () => {
108-
assert.throws(() => new watson.VisualRecognitionV3(), /use_unauthenticated/);
109-
assert.throws(() => new watson.VisualRecognitionV3({}), /use_unauthenticated/);
108+
assert.throws(() => new watson.VisualRecognitionV3(), /Insufficient credentials/);
109+
assert.throws(() => new watson.VisualRecognitionV3({}), /Insufficient credentials/);
110110
assert.throws(
111111
() => new watson.VisualRecognitionV3({ version: '2016-05-20' }),
112-
/use_unauthenticated/
112+
/Insufficient credentials/
113113
);
114114
assert.throws(
115115
() => new watson.VisualRecognitionV3({ username: 'foo' }),
116-
/use_unauthenticated/
116+
/Insufficient credentials/
117117
);
118118
});
119119

test/unit/test.wrapper.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ describe('wrapper', function() {
3939
use_unauthenticated: false,
4040
version: 'v1',
4141
});
42-
}, /use_unauthenticated/);
42+
}, /Insufficient credentials/);
4343
});
4444

4545
it('should check for missing version', function() {

0 commit comments

Comments
 (0)