Skip to content

Commit de96e0c

Browse files
authored
Merge pull request #123 from particle-iot/feature/expiring-tokens
Add more ways to invalidate access tokens
2 parents bccd319 + 35cdc7a commit de96e0c

File tree

2 files changed

+78
-3
lines changed

2 files changed

+78
-3
lines changed

src/Particle.js

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,16 +123,23 @@ class Particle {
123123
* @param {Object} options.auth Access token
124124
* @param {Object} options.mfaToken Token given from previous step to
125125
* @param {Object} options.otp Current one-time-password generated from the authentication app
126+
* @param {Boolean} options.invalidateTokens Should all tokens be invalidated
126127
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
127128
* @param {Object} [options.context] Request context
128129
* @returns {Promise} A promise
129130
*/
130-
confirmMfa({ mfaToken, otp, auth, headers, context }){
131+
confirmMfa({ mfaToken, otp, invalidateTokens = false, auth, headers, context }){
132+
let data = { mfa_token: mfaToken, otp };
133+
134+
if (invalidateTokens) {
135+
data.invalidate_tokens = true;
136+
}
137+
131138
return this.post({
132139
uri: '/v1/user/mfa-enable',
133140
auth,
134141
headers,
135-
data: { mfa_token: mfaToken, otp },
142+
data,
136143
context
137144
});
138145
}
@@ -297,6 +304,23 @@ class Particle {
297304
});
298305
}
299306

307+
/**
308+
* Revoke all active access tokens
309+
* @param {Object} options Options for this API call
310+
* @param {String} options.auth Access Token
311+
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
312+
* @param {Object} [options.context] Request context
313+
* @returns {Promise} A promise
314+
*/
315+
deleteActiveAccessTokens({ auth, headers, context }){
316+
return this.delete({
317+
uri: '/v1/access_tokens',
318+
auth,
319+
headers,
320+
context
321+
});
322+
}
323+
300324
/**
301325
* Delete the current user
302326
* @param {Object} options Options for this API call
@@ -1065,12 +1089,18 @@ class Particle {
10651089
* @param {String} options.auth Access Token
10661090
* @param {String} options.currentPassword Current password
10671091
* @param {String} options.username New email
1092+
* @param {Boolean} options.invalidateTokens Should all tokens be invalidated
10681093
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
10691094
* @param {Object} [options.context] Request context
10701095
* @returns {Promise} A promise
10711096
*/
1072-
changeUsername({ currentPassword, username, auth, headers, context }){
1097+
changeUsername({ currentPassword, username, invalidateTokens = false, auth, headers, context }){
10731098
const data = { username, current_password: currentPassword };
1099+
1100+
if (invalidateTokens) {
1101+
data.invalidate_tokens = true;
1102+
}
1103+
10741104
return this.put({ uri: '/v1/user', auth, headers, data, context });
10751105
}
10761106

test/Particle.spec.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,22 @@ describe('ParticleAPI', () => {
218218
});
219219
});
220220
});
221+
it('allows invalidating tokens', () => {
222+
return api.confirmMfa(Object.assign({ invalidateTokens: true }, props)).then((results) => {
223+
results.should.eql({
224+
uri: '/v1/user/mfa-enable',
225+
method: 'post',
226+
auth: props.auth,
227+
headers: props.headers,
228+
data: {
229+
otp: props.otp,
230+
mfa_token: props.mfaToken,
231+
invalidate_tokens: true
232+
},
233+
context: {}
234+
});
235+
});
236+
});
221237
});
222238

223239
describe('.disableMfa', () => {
@@ -306,6 +322,18 @@ describe('ParticleAPI', () => {
306322
});
307323
});
308324

325+
describe('.deleteActiveAccessTokens', () => {
326+
it('sends request', () => {
327+
return api.deleteActiveAccessTokens(props).then((results) => {
328+
results.should.match({
329+
method: 'delete',
330+
uri: '/v1/access_tokens',
331+
auth: props.auth,
332+
});
333+
});
334+
});
335+
});
336+
309337
describe('.listAccessTokens', () => {
310338
it('sends credentials', () => {
311339
return api.listAccessTokens(props).then(({ auth }) => {
@@ -1356,6 +1384,23 @@ describe('ParticleAPI', () => {
13561384
});
13571385
});
13581386
});
1387+
it('allows invalidating tokens', () => {
1388+
return api.changeUsername({ auth: 'X', currentPassword: 'blabla', username: 'john@skul.ly', invalidateTokens: true })
1389+
.then((results) => {
1390+
results.should.eql({
1391+
uri: '/v1/user',
1392+
method: 'put',
1393+
auth: 'X',
1394+
headers: undefined,
1395+
data: {
1396+
current_password: 'blabla',
1397+
username: 'john@skul.ly',
1398+
invalidate_tokens: true
1399+
},
1400+
context: {}
1401+
});
1402+
});
1403+
});
13591404
});
13601405

13611406
describe('.changeUserPassword', () => {

0 commit comments

Comments
 (0)