Skip to content

Commit 89e320e

Browse files
committed
Supply state as info.
1 parent bd43960 commit 89e320e

File tree

2 files changed

+152
-2
lines changed

2 files changed

+152
-2
lines changed

lib/strategy.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,10 @@ OAuth2Strategy.prototype.authenticate = function(req, options) {
149149
}
150150

151151
if (req.query && req.query.code) {
152-
function loaded(err, ok, info) {
152+
function loaded(err, ok, state) {
153153
if (err) { return self.error(err); }
154154
if (!ok) {
155-
return self.fail(info, 403);
155+
return self.fail(state, 403);
156156
}
157157

158158
var code = req.query.code;
@@ -171,6 +171,9 @@ OAuth2Strategy.prototype.authenticate = function(req, options) {
171171
function verified(err, user, info) {
172172
if (err) { return self.error(err); }
173173
if (!user) { return self.fail(info); }
174+
175+
info = info || {};
176+
if (state) { info.state = state; }
174177
self.success(user, info);
175178
}
176179

test/oauth2.state.custom.test.js

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,4 +247,151 @@ describe('OAuth2Strategy', function() {
247247

248248
}); // with custom state store that accepts meta argument
249249

250+
251+
describe('with custom state store that accepts meta argument and supplies state', function() {
252+
function CustomStore() {
253+
}
254+
255+
CustomStore.prototype.verify = function(req, state, meta, cb) {
256+
req.customStoreVerifyCalled = req.customStoreVerifyCalled ? req.customStoreVerifyCalled++ : 1;
257+
return cb(null, true, { returnTo: 'http://www.example.com/' });
258+
};
259+
260+
describe('processing response to authorization request', function() {
261+
262+
describe('that was approved without info', function() {
263+
var strategy = new OAuth2Strategy({
264+
authorizationURL: 'https://www.example.com/oauth2/authorize',
265+
tokenURL: 'https://www.example.com/oauth2/token',
266+
clientID: 'ABC123',
267+
clientSecret: 'secret',
268+
callbackURL: 'https://www.example.net/auth/example/callback',
269+
store: new CustomStore()
270+
},
271+
function(accessToken, refreshToken, profile, done) {
272+
if (accessToken !== '2YotnFZFEjr1zCsicMWpAA') { return done(new Error('incorrect accessToken argument')); }
273+
if (refreshToken !== 'tGzv3JOkF0XG5Qx2TlKWIA') { return done(new Error('incorrect refreshToken argument')); }
274+
if (typeof profile !== 'object') { return done(new Error('incorrect profile argument')); }
275+
if (Object.keys(profile).length !== 0) { return done(new Error('incorrect profile argument')); }
276+
277+
return done(null, { id: '1234' });
278+
});
279+
280+
strategy._oauth2.getOAuthAccessToken = function(code, options, callback) {
281+
if (code !== 'SplxlOBeZQQYbYS6WxSbIA') { return callback(new Error('incorrect code argument')); }
282+
if (options.grant_type !== 'authorization_code') { return callback(new Error('incorrect options.grant_type argument')); }
283+
if (options.redirect_uri !== 'https://www.example.net/auth/example/callback') { return callback(new Error('incorrect options.redirect_uri argument')); }
284+
285+
return callback(null, '2YotnFZFEjr1zCsicMWpAA', 'tGzv3JOkF0XG5Qx2TlKWIA', { token_type: 'example' });
286+
}
287+
288+
var request
289+
, user
290+
, info;
291+
292+
before(function(done) {
293+
chai.passport.use(strategy)
294+
.success(function(u, i) {
295+
user = u;
296+
info = i;
297+
done();
298+
})
299+
.req(function(req) {
300+
request = req;
301+
302+
req.url = '/auth/example/callback';
303+
req.query = {};
304+
req.query.code = 'SplxlOBeZQQYbYS6WxSbIA';
305+
req.query.state = 'foos7473';
306+
})
307+
.authenticate();
308+
});
309+
310+
it('should supply user', function() {
311+
expect(user).to.be.an.object;
312+
expect(user.id).to.equal('1234');
313+
});
314+
315+
it('should supply info with state', function() {
316+
expect(info).to.be.an.object;
317+
expect(Object.keys(info)).to.have.length(1);
318+
expect(info.state).to.be.an.object;
319+
expect(info.state.returnTo).to.equal('http://www.example.com/');
320+
});
321+
322+
it('should verify state using custom store', function() {
323+
expect(request.customStoreVerifyCalled).to.equal(1);
324+
});
325+
}); // that was approved without info
326+
327+
describe('that was approved with info', function() {
328+
var strategy = new OAuth2Strategy({
329+
authorizationURL: 'https://www.example.com/oauth2/authorize',
330+
tokenURL: 'https://www.example.com/oauth2/token',
331+
clientID: 'ABC123',
332+
clientSecret: 'secret',
333+
callbackURL: 'https://www.example.net/auth/example/callback',
334+
store: new CustomStore()
335+
},
336+
function(accessToken, refreshToken, profile, done) {
337+
if (accessToken !== '2YotnFZFEjr1zCsicMWpAA') { return done(new Error('incorrect accessToken argument')); }
338+
if (refreshToken !== 'tGzv3JOkF0XG5Qx2TlKWIA') { return done(new Error('incorrect refreshToken argument')); }
339+
if (typeof profile !== 'object') { return done(new Error('incorrect profile argument')); }
340+
if (Object.keys(profile).length !== 0) { return done(new Error('incorrect profile argument')); }
341+
342+
return done(null, { id: '1234' }, { message: 'Hello' });
343+
});
344+
345+
strategy._oauth2.getOAuthAccessToken = function(code, options, callback) {
346+
if (code !== 'SplxlOBeZQQYbYS6WxSbIA') { return callback(new Error('incorrect code argument')); }
347+
if (options.grant_type !== 'authorization_code') { return callback(new Error('incorrect options.grant_type argument')); }
348+
if (options.redirect_uri !== 'https://www.example.net/auth/example/callback') { return callback(new Error('incorrect options.redirect_uri argument')); }
349+
350+
return callback(null, '2YotnFZFEjr1zCsicMWpAA', 'tGzv3JOkF0XG5Qx2TlKWIA', { token_type: 'example' });
351+
}
352+
353+
var request
354+
, user
355+
, info;
356+
357+
before(function(done) {
358+
chai.passport.use(strategy)
359+
.success(function(u, i) {
360+
user = u;
361+
info = i;
362+
done();
363+
})
364+
.req(function(req) {
365+
request = req;
366+
367+
req.url = '/auth/example/callback';
368+
req.query = {};
369+
req.query.code = 'SplxlOBeZQQYbYS6WxSbIA';
370+
req.query.state = 'foos7473';
371+
})
372+
.authenticate();
373+
});
374+
375+
it('should supply user', function() {
376+
expect(user).to.be.an.object;
377+
expect(user.id).to.equal('1234');
378+
});
379+
380+
it('should supply info with state', function() {
381+
expect(info).to.be.an.object;
382+
expect(Object.keys(info)).to.have.length(2);
383+
expect(info.message).to.equal('Hello');
384+
expect(info.state).to.be.an.object;
385+
expect(info.state.returnTo).to.equal('http://www.example.com/');
386+
});
387+
388+
it('should verify state using custom store', function() {
389+
expect(request.customStoreVerifyCalled).to.equal(1);
390+
});
391+
}); // that was approved with info
392+
393+
}); // processing response to authorization request
394+
395+
}); // with custom state store that accepts meta argument and supplies state
396+
250397
});

0 commit comments

Comments
 (0)