diff --git a/lib/strategy.js b/lib/strategy.js index 0902ec5..07b87f1 100644 --- a/lib/strategy.js +++ b/lib/strategy.js @@ -252,7 +252,7 @@ OAuth2Strategy.prototype.authenticate = function(req, options) { } var state = options.state; - if (state && typeof state !== 'object') { + if (state && typeof state == 'string') { // NOTE: In passport-oauth2@1.5.0 and earlier, `state` could be passed as // an object. However, it would result in an empty string being // serialized as the value of the query parameter by `url.format()`, diff --git a/test/oauth2.pkce.test.js b/test/oauth2.pkce.test.js index 2b13b15..90a5f47 100644 --- a/test/oauth2.pkce.test.js +++ b/test/oauth2.pkce.test.js @@ -127,6 +127,74 @@ describe('OAuth2Strategy', function() { }); }); + describe('handling a request to be redirected for authorization with state set to boolean true', function() { + var request, url; + + before(function(done) { + chai.passport.use(strategy) + .redirect(function(u) { + url = u; + done(); + }) + .req(function(req) { + request = req; + req.session = {}; + }) + .authenticate({ state: true }); + }); + + it('should be redirected', function() { + var u = uri.parse(url, true); + expect(u.query.state).to.have.length(24); + expect(u.query.code_challenge).to.have.length(43); + expect(u.query.code_challenge).to.equal('E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM') + expect(u.query.code_challenge_method).to.equal('S256'); + }); + + it('should save verifier in session', function() { + var u = uri.parse(url, true); + expect(request.session['oauth2:www.example.com'].state.handle).to.have.length(24); + expect(request.session['oauth2:www.example.com'].state.handle).to.equal(u.query.state); + expect(request.session['oauth2:www.example.com'].state.code_verifier).to.have.length(43); + expect(request.session['oauth2:www.example.com'].state.code_verifier).to.equal('dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'); + expect(request.session['oauth2:www.example.com'].state.state).to.equal(true); + }); + }); + + describe('handling a request to be redirected for authorization with state set to boolean false', function() { + var request, url; + + before(function(done) { + chai.passport.use(strategy) + .redirect(function(u) { + url = u; + done(); + }) + .req(function(req) { + request = req; + req.session = {}; + }) + .authenticate({ state: false }); + }); + + it('should be redirected', function() { + var u = uri.parse(url, true); + expect(u.query.state).to.have.length(24); + expect(u.query.code_challenge).to.have.length(43); + expect(u.query.code_challenge).to.equal('E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM') + expect(u.query.code_challenge_method).to.equal('S256'); + }); + + it('should save verifier in session', function() { + var u = uri.parse(url, true); + expect(request.session['oauth2:www.example.com'].state.handle).to.have.length(24); + expect(request.session['oauth2:www.example.com'].state.handle).to.equal(u.query.state); + expect(request.session['oauth2:www.example.com'].state.code_verifier).to.have.length(43); + expect(request.session['oauth2:www.example.com'].state.code_verifier).to.equal('dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'); + expect(request.session['oauth2:www.example.com'].state.state).to.be.undefined; + }); + }); + describe('that redirects to service provider with other data in session', function() { var request, url; diff --git a/test/oauth2.store.pkce.test.js b/test/oauth2.store.pkce.test.js index 8ca1d00..8fb6bf4 100644 --- a/test/oauth2.store.pkce.test.js +++ b/test/oauth2.store.pkce.test.js @@ -112,6 +112,74 @@ describe('OAuth2Strategy', function() { }); }); + describe('handling a request to be redirected for authorization with state as boolean true', function() { + var request, url; + + before(function(done) { + chai.passport.use(strategy) + .redirect(function(u) { + url = u; + done(); + }) + .req(function(req) { + request = req; + req.session = {}; + }) + .authenticate({ state: true }); + }); + + it('should be redirected', function() { + var u = uri.parse(url, true); + expect(u.query.state).to.have.length(24); + expect(u.query.code_challenge).to.have.length(43); + expect(u.query.code_challenge).to.equal('E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM') + expect(u.query.code_challenge_method).to.equal('S256'); + }); + + it('should save verifier in session', function() { + var u = uri.parse(url, true); + expect(request.session['oauth2:www.example.com'].state.handle).to.have.length(24); + expect(request.session['oauth2:www.example.com'].state.handle).to.equal(u.query.state); + expect(request.session['oauth2:www.example.com'].state.code_verifier).to.have.length(43); + expect(request.session['oauth2:www.example.com'].state.code_verifier).to.equal('dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'); + expect(request.session['oauth2:www.example.com'].state.state).to.equal(true); + }); + }); + + describe('handling a request to be redirected for authorization with state as boolean false', function() { + var request, url; + + before(function(done) { + chai.passport.use(strategy) + .redirect(function(u) { + url = u; + done(); + }) + .req(function(req) { + request = req; + req.session = {}; + }) + .authenticate({ state: false }); + }); + + it('should be redirected', function() { + var u = uri.parse(url, true); + expect(u.query.state).to.have.length(24); + expect(u.query.code_challenge).to.have.length(43); + expect(u.query.code_challenge).to.equal('E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM') + expect(u.query.code_challenge_method).to.equal('S256'); + }); + + it('should save verifier in session', function() { + var u = uri.parse(url, true); + expect(request.session['oauth2:www.example.com'].state.handle).to.have.length(24); + expect(request.session['oauth2:www.example.com'].state.handle).to.equal(u.query.state); + expect(request.session['oauth2:www.example.com'].state.code_verifier).to.have.length(43); + expect(request.session['oauth2:www.example.com'].state.code_verifier).to.equal('dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'); + expect(request.session['oauth2:www.example.com'].state.state).to.be.undefined; + }); + }); + describe('that redirects to service provider with other data in session', function() { var request, url; diff --git a/test/oauth2.store.test.js b/test/oauth2.store.test.js index a63a0e9..c23743e 100644 --- a/test/oauth2.store.test.js +++ b/test/oauth2.store.test.js @@ -83,6 +83,66 @@ describe('OAuth2Strategy', function() { }); }); // that redirects to service provider with state + describe('that redirects to service provider with state set to boolean true', function() { + var request, url; + + before(function(done) { + chai.passport.use(strategy) + .redirect(function(u) { + url = u; + done(); + }) + .req(function(req) { + request = req; + req.session = {}; + }) + .authenticate({ state: true }); + }); + + it('should be redirected', function() { + var u = uri.parse(url, true); + expect(u.query.state).to.have.length(24); + }); + + it('should save state in session', function() { + var u = uri.parse(url, true); + + expect(request.session['oauth2:www.example.com'].state.handle).to.have.length(24); + expect(request.session['oauth2:www.example.com'].state.handle).to.equal(u.query.state); + expect(request.session['oauth2:www.example.com'].state.state).to.equal(true); + }); + }); // that redirects to service provider with state set to boolean true + + describe('that redirects to service provider with state set to boolean false', function() { + var request, url; + + before(function(done) { + chai.passport.use(strategy) + .redirect(function(u) { + url = u; + done(); + }) + .req(function(req) { + request = req; + req.session = {}; + }) + .authenticate({ state: false }); + }); + + it('should be redirected', function() { + var u = uri.parse(url, true); + expect(u.query.state).to.have.length(24); + }); + + it('should save state in session', function() { + var u = uri.parse(url, true); + + expect(request.session['oauth2:www.example.com'].state.handle).to.have.length(24); + expect(request.session['oauth2:www.example.com'].state.handle).to.equal(u.query.state); + expect(request.session['oauth2:www.example.com'].state.state).to.be.undefined; + }); + }); // that redirects to service provider with state set to boolean false + describe('that redirects to service provider with other data in session', function() { var request, url;