Skip to content

Commit 463b517

Browse files
authored
Merge pull request #309 from dhensby/pulls/scope-fix
fix: explicitly support array of strings for AuthenticateHandler.options
2 parents f511c32 + 47ee118 commit 463b517

File tree

3 files changed

+102
-6
lines changed

3 files changed

+102
-6
lines changed

index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ declare namespace OAuth2Server {
168168
/**
169169
* The scope(s) to authenticate.
170170
*/
171-
scope?: string | undefined;
171+
scope?: string[];
172172

173173
/**
174174
* Set the X-Accepted-OAuth-Scopes HTTP header on response objects.

lib/handlers/authenticate-handler.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class AuthenticateHandler {
4747
this.addAuthorizedScopesHeader = options.addAuthorizedScopesHeader;
4848
this.allowBearerTokensInQueryString = options.allowBearerTokensInQueryString;
4949
this.model = options.model;
50-
this.scope = parseScope(options.scope);
50+
this.scope = Array.isArray(options.scope) ? options.scope : parseScope(options.scope);
5151
}
5252

5353
/**

test/integration/handlers/authenticate-handler_test.js

Lines changed: 100 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,35 @@ describe('AuthenticateHandler integration', function() {
242242
});
243243

244244
it('should return an access token', function() {
245+
const accessToken = {
246+
user: {},
247+
accessTokenExpiresAt: new Date(new Date().getTime() + 10000)
248+
};
249+
const model = {
250+
getAccessToken: function() {
251+
return accessToken;
252+
},
253+
verifyScope: function() {
254+
return true;
255+
}
256+
};
257+
const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: ['foo'] });
258+
const request = new Request({
259+
body: {},
260+
headers: { 'Authorization': 'Bearer foo' },
261+
method: {},
262+
query: {}
263+
});
264+
const response = new Response({ body: {}, headers: {} });
265+
266+
return handler.handle(request, response)
267+
.then(function(data) {
268+
data.should.equal(accessToken);
269+
})
270+
.catch(should.fail);
271+
});
272+
273+
it('should return an access token (deprecated)', function() {
245274
const accessToken = {
246275
user: {},
247276
accessTokenExpiresAt: new Date(new Date().getTime() + 10000)
@@ -515,7 +544,7 @@ describe('AuthenticateHandler integration', function() {
515544
});
516545

517546
describe('verifyScope()', function() {
518-
it('should throw an error if `scope` is insufficient', function() {
547+
it('should throw an error if `scope` is insufficient (deprecated)', function() {
519548
const model = {
520549
getAccessToken: function() {},
521550
verifyScope: function() {
@@ -532,7 +561,48 @@ describe('AuthenticateHandler integration', function() {
532561
});
533562
});
534563

564+
it('should throw an error if `scope` is insufficient', function() {
565+
const model = {
566+
getAccessToken: function() {},
567+
verifyScope: function() {
568+
return false;
569+
}
570+
};
571+
const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: ['foo'] });
572+
573+
return handler.verifyScope(['foo'])
574+
.then(should.fail)
575+
.catch(function(e) {
576+
e.should.be.an.instanceOf(InsufficientScopeError);
577+
e.message.should.equal('Insufficient scope: authorized scope is insufficient');
578+
});
579+
});
580+
581+
it('should support promises (deprecated)', function() {
582+
const model = {
583+
getAccessToken: function() {},
584+
verifyScope: function() {
585+
return true;
586+
}
587+
};
588+
const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' });
589+
590+
handler.verifyScope(['foo']).should.be.an.instanceOf(Promise);
591+
});
592+
535593
it('should support promises', function() {
594+
const model = {
595+
getAccessToken: function() {},
596+
verifyScope: function() {
597+
return true;
598+
}
599+
};
600+
const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: ['foo'] });
601+
602+
handler.verifyScope(['foo']).should.be.an.instanceOf(Promise);
603+
});
604+
605+
it('should support non-promises (deprecated)', function() {
536606
const model = {
537607
getAccessToken: function() {},
538608
verifyScope: function() {
@@ -551,7 +621,7 @@ describe('AuthenticateHandler integration', function() {
551621
return true;
552622
}
553623
};
554-
const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' });
624+
const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: ['foo'] });
555625

556626
handler.verifyScope(['foo']).should.be.an.instanceOf(Promise);
557627
});
@@ -571,7 +641,7 @@ describe('AuthenticateHandler integration', function() {
571641
response.headers.should.not.have.property('x-accepted-oauth-scopes');
572642
});
573643

574-
it('should set the `X-Accepted-OAuth-Scopes` header if `scope` is specified', function() {
644+
it('should set the `X-Accepted-OAuth-Scopes` header if `scope` is specified (deprecated)', function() {
575645
const model = {
576646
getAccessToken: function() {},
577647
verifyScope: function() {}
@@ -584,6 +654,19 @@ describe('AuthenticateHandler integration', function() {
584654
response.get('X-Accepted-OAuth-Scopes').should.equal('foo bar');
585655
});
586656

657+
it('should set the `X-Accepted-OAuth-Scopes` header if `scope` is specified', function() {
658+
const model = {
659+
getAccessToken: function() {},
660+
verifyScope: function() {}
661+
};
662+
const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: false, model: model, scope: ['foo', 'bar'] });
663+
const response = new Response({ body: {}, headers: {} });
664+
665+
handler.updateResponse(response, { scope: ['foo', 'biz'] });
666+
667+
response.get('X-Accepted-OAuth-Scopes').should.equal('foo bar');
668+
});
669+
587670
it('should not set the `X-Authorized-OAuth-Scopes` header if `scope` is not specified', function() {
588671
const model = {
589672
getAccessToken: function() {},
@@ -597,7 +680,7 @@ describe('AuthenticateHandler integration', function() {
597680
response.headers.should.not.have.property('x-oauth-scopes');
598681
});
599682

600-
it('should set the `X-Authorized-OAuth-Scopes` header', function() {
683+
it('should set the `X-Authorized-OAuth-Scopes` header (deprecated)', function() {
601684
const model = {
602685
getAccessToken: function() {},
603686
verifyScope: function() {}
@@ -609,5 +692,18 @@ describe('AuthenticateHandler integration', function() {
609692

610693
response.get('X-OAuth-Scopes').should.equal('foo biz');
611694
});
695+
696+
it('should set the `X-Authorized-OAuth-Scopes` header', function() {
697+
const model = {
698+
getAccessToken: function() {},
699+
verifyScope: function() {}
700+
};
701+
const handler = new AuthenticateHandler({ addAcceptedScopesHeader: false, addAuthorizedScopesHeader: true, model: model, scope: ['foo', 'bar'] });
702+
const response = new Response({ body: {}, headers: {} });
703+
704+
handler.updateResponse(response, { scope: ['foo', 'biz'] });
705+
706+
response.get('X-OAuth-Scopes').should.equal('foo biz');
707+
});
612708
});
613709
});

0 commit comments

Comments
 (0)