Skip to content

Commit

Permalink
Simplify PKCE option to allow boolean value.
Browse files Browse the repository at this point in the history
  • Loading branch information
jaredhanson committed Mar 13, 2019
1 parent d75cd7b commit 59de2da
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 5 deletions.
2 changes: 1 addition & 1 deletion lib/strategy.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ function OAuth2Strategy(options, verify) {
this._callbackURL = options.callbackURL;
this._scope = options.scope;
this._scopeSeparator = options.scopeSeparator || ' ';
this._pkceMethod = options.pkceMethod;
this._pkceMethod = (options.pkce === true) ? 'S256' : options.pkce;
this._key = options.sessionKey || ('oauth2:' + url.parse(options.authorizationURL).hostname);

if (options.store) {
Expand Down
121 changes: 117 additions & 4 deletions test/oauth2.pkce.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,119 @@ var chai = require('chai')

describe('OAuth2Strategy', function() {

describe('with PKCE true transformation method', function() {
var mockCrypto = {
pseudoRandomBytes: function(len) {
if (len !== 32) { throw new Error('xyz'); }
// https://tools.ietf.org/html/rfc7636#appendix-B
return new Buffer(
[116, 24, 223, 180, 151, 153, 224, 37, 79, 250, 96, 125, 216, 173,
187, 186, 22, 212, 37, 77, 105, 214, 191, 240, 91, 88, 5, 88, 83,
132, 141, 121]
);
}
}

var OAuth2Strategy = require('proxyquire')('../lib/strategy', { crypto: mockCrypto });
var strategy = new OAuth2Strategy({
authorizationURL: 'https://www.example.com/oauth2/authorize',
tokenURL: 'https://www.example.com/oauth2/token',
clientID: 'ABC123',
clientSecret: 'secret',
callbackURL: 'https://www.example.net/auth/example/callback',
state: true,
pkce: true
},
function(accessToken, refreshToken, profile, done) {
if (accessToken == '2YotnFZFEjr1zCsicMWpAA' && refreshToken == 'tGzv3JOkF0XG5Qx2TlKWIA') {
return done(null, { id: '1234' }, { message: 'Hello' });
}
return done(null, false);
});

strategy._oauth2.getOAuthAccessToken = function(code, options, callback) {
if (code !== 'SplxlOBeZQQYbYS6WxSbIA') { return callback(new Error('incorrect code argument')); }
if (options.grant_type !== 'authorization_code') { return callback(new Error('incorrect options.grant_type argument')); }
if (options.redirect_uri !== 'https://www.example.net/auth/example/callback') { return callback(new Error('incorrect options.redirect_uri argument')); }
if (options.code_verifier !== 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk') { return callback(new Error('incorrect options.verifier loaded from session')); }

return callback(null, '2YotnFZFEjr1zCsicMWpAA', 'tGzv3JOkF0XG5Qx2TlKWIA', { token_type: 'example' });
}

describe('handling a request to be redirected for authorization', 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();
});

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.verifier).to.have.length(43);
expect(request.session['oauth2:www.example.com'].state.verifier).to.equal('dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk');
});
});

describe('processing response to authorization request', function() {
var request
, user
, info;

before(function(done) {
chai.passport.use(strategy)
.success(function(u, i) {
user = u;
info = i;
done();
})
.req(function(req) {
request = req;

req.query = {};
req.query.code = 'SplxlOBeZQQYbYS6WxSbIA';
req.query.state = 'DkbychwKu8kBaJoLE5yeR5NK';
req.session = {};
req.session['oauth2:www.example.com'] = {};
req.session['oauth2:www.example.com']['state'] = { handle: 'DkbychwKu8kBaJoLE5yeR5NK', verifier: 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk' };
})
.authenticate();
});

it('should supply user', function() {
expect(user).to.be.an.object;
expect(user.id).to.equal('1234');
});

it('should supply info', function() {
expect(info).to.be.an.object;
expect(info.message).to.equal('Hello');
});

it('should remove state with verifier from session', function() {
expect(request.session['oauth2:www.example.com']).to.be.undefined;
});
});
});

describe('with PKCE plain transformation method', function() {
var mockCrypto = {
pseudoRandomBytes: function(len) {
Expand All @@ -25,7 +138,7 @@ describe('OAuth2Strategy', function() {
clientSecret: 'secret',
callbackURL: 'https://www.example.net/auth/example/callback',
state: true,
pkceMethod: 'plain'
pkce: 'plain'
},
function(accessToken, refreshToken, profile, done) {
if (accessToken == '2YotnFZFEjr1zCsicMWpAA' && refreshToken == 'tGzv3JOkF0XG5Qx2TlKWIA') {
Expand Down Expand Up @@ -138,7 +251,7 @@ describe('OAuth2Strategy', function() {
clientSecret: 'secret',
callbackURL: 'https://www.example.net/auth/example/callback',
state: true,
pkceMethod: 'S256'
pkce: 'S256'
},
function(accessToken, refreshToken, profile, done) {
if (accessToken == '2YotnFZFEjr1zCsicMWpAA' && refreshToken == 'tGzv3JOkF0XG5Qx2TlKWIA') {
Expand Down Expand Up @@ -253,7 +366,7 @@ describe('OAuth2Strategy', function() {
clientSecret: 'secret',
callbackURL: 'https://www.example.net/auth/example/callback',
state: true,
pkceMethod: 'unknown'
pkce: 'unknown'
},
function(accessToken, refreshToken, profile, done) {
if (accessToken == '2YotnFZFEjr1zCsicMWpAA' && refreshToken == 'tGzv3JOkF0XG5Qx2TlKWIA') {
Expand Down Expand Up @@ -292,7 +405,7 @@ describe('OAuth2Strategy', function() {
clientSecret: 'secret',
callbackURL: 'https://www.example.net/auth/example/callback',
state: true,
pkceMethod: 'S256'
pkce: 'S256'
},
function(accessToken, refreshToken, profile, done) {
if (accessToken == '2YotnFZFEjr1zCsicMWpAA' && refreshToken == 'tGzv3JOkF0XG5Qx2TlKWIA') {
Expand Down

0 comments on commit 59de2da

Please sign in to comment.