├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── etc └── conf.json ├── lib ├── index.js ├── strategy.js └── utils.js ├── package.json └── test ├── bootstrap └── node.js ├── package.test.js ├── strategy.error.test.js ├── strategy.fail.test.js ├── strategy.fields.test.js ├── strategy.normal.test.js ├── strategy.options.test.js ├── strategy.passreq.test.js └── strategy.test.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: jaredhanson 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ** READ THIS FIRST! ** 2 | 3 | #### Are you looking for help? 4 | 5 | Reminder: The issue tracker is not a support forum. 6 | 7 | Issues should only be filed in this project once they are able to be reproduced 8 | and confirmed as a flaw in the software or incorrect information in associated 9 | documention. 10 | 11 | If you are encountering problems integrating this module into your application, 12 | please post a question on the [discussion forum](https://github.com/passport/discuss) 13 | rather than filing an issue. 14 | 15 | #### Is this a security issue? 16 | 17 | Do not open issues that might have security implications. Potential security 18 | vulnerabilities should be reported privately to jaredhanson@gmail.com. Once any 19 | vulerabilities have been repaired, the details will be disclosed publicly in a 20 | responsible manner. This also allows time for coordinating with affected parties 21 | in order to mitigate negative consequences. 22 | 23 | 24 | If neither of the above two scenarios apply to your situation, you should open 25 | an issue. Delete this paragraph and the text above, and fill in the information 26 | requested below. 27 | 28 | 29 | 30 | 31 | 32 | 33 | ### Expected behavior 34 | 35 | 36 | 37 | ### Actual behavior 38 | 39 | 40 | 41 | ### Steps to reproduce 42 | 43 | 44 | 45 | ```js 46 | // Format code using Markdown code blocks 47 | ``` 48 | 49 | ### Environment 50 | 51 | * Operating System: 52 | * Node version: 53 | * passport version: 54 | * passport-local version: 55 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ** READ THIS FIRST! ** 2 | 3 | #### Are you implementing a new feature? 4 | 5 | Requests for new features should first be discussed on the [developer forum](https://github.com/passport/develop). 6 | This allows the community to gather feedback and assess whether or not there is 7 | an existing way to achieve the desired functionality. 8 | 9 | If it is determined that a new feature needs to be implemented, include a link 10 | to the relevant discussion along with the pull request. 11 | 12 | #### Is this a security patch? 13 | 14 | Do not open pull requests that might have security implications. Potential 15 | security vulnerabilities should be reported privately to jaredhanson@gmail.com. 16 | Once any vulerabilities have been repaired, the details will be disclosed 17 | publicly in a responsible manner. This also allows time for coordinating with 18 | affected parties in order to mitigate negative consequences. 19 | 20 | 21 | If neither of the above two scenarios apply to your situation, you should open 22 | a pull request. Delete this paragraph and the text above, and fill in the 23 | information requested below. 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | ### Checklist 33 | 34 | 35 | 36 | 37 | - [ ] I have read the [CONTRIBUTING](https://github.com/jaredhanson/passport-local/blob/master/CONTRIBUTING.md) guidelines. 38 | - [ ] I have added test cases which verify the correct operation of this feature or patch. 39 | - [ ] I have added documentation pertaining to this feature or patch. 40 | - [ ] The automated test suite (`$ make test`) executes successfully. 41 | - [ ] The automated code linting (`$ make lint`) executes successfully. 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | reports/ 3 | 4 | # Node.js 5 | node_modules/ 6 | npm-debug.log 7 | 8 | # Mac OS X 9 | .DS_Store 10 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "bitwise": true, 4 | "camelcase": true, 5 | "curly": true, 6 | "forin": true, 7 | "immed": true, 8 | "latedef": true, 9 | "newcap": true, 10 | "noarg": true, 11 | "noempty": true, 12 | "nonew": true, 13 | "quotmark": "single", 14 | "undef": true, 15 | "unused": true, 16 | "trailing": true, 17 | "laxcomma": true 18 | } 19 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | README.md 3 | build/ 4 | docs/ 5 | examples/ 6 | reports/ 7 | support/ 8 | test/ 9 | 10 | # Node.js 11 | .npmignore 12 | node_modules/ 13 | npm-debug.log 14 | 15 | # Mac OS X 16 | .DS_Store 17 | 18 | # Git 19 | .git* 20 | 21 | # Utilities 22 | .jshintrc 23 | .travis.yml 24 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: "node_js" 2 | node_js: 3 | - "11" 4 | - "10" 5 | - "9" 6 | - "8" 7 | - "7" 8 | - "6" 9 | - "5" 10 | - "4" 11 | - "3" # io.js 12 | - "2" # io.js 13 | - "1" # io.js 14 | - "0.12" 15 | - "0.10" 16 | - "0.8" 17 | 18 | 19 | # NOTE: `istanbul` and `coveralls` are pinned for compatibility with node 0.8. 20 | before_install: 21 | - "npm install -g istanbul@0.2.2" 22 | - "npm install -g coveralls@2.11.4" 23 | 24 | script: 25 | - "make check" 26 | 27 | after_success: 28 | - "make report-cov" 29 | 30 | sudo: false 31 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | ### Tests 4 | 5 | The test suite is located in the `test/` directory. All new features are 6 | expected to have corresponding test cases with complete code coverage. Patches 7 | that increase test coverage are happily accepted. 8 | 9 | Ensure that the test suite passes by executing: 10 | 11 | ```bash 12 | $ make test 13 | ``` 14 | 15 | Coverage reports can be generated and viewed by executing: 16 | 17 | ```bash 18 | $ make test-cov 19 | $ make view-cov 20 | ``` 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2014 Jared Hanson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include node_modules/make-node/main.mk 2 | 3 | MOCHAFLAGS = --require ./test/bootstrap/node 4 | JSDOCFLAGS = -c etc/conf.json 5 | 6 | 7 | # Perform self-tests. 8 | check: test 9 | 10 | apidoc: $(SOURCES) 11 | $(JSDOC) $(JSDOCFLAGS) -t node_modules/@www.passportjs.org/jsdoc-template -d wwwhtml $^ 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # passport-local 2 | 3 | [Passport](https://www.passportjs.org/) strategy for authenticating with a 4 | username and password. 5 | 6 | This module lets you authenticate using a username and password in your Node.js 7 | applications. By plugging into Passport, password-based sign in can be easily 8 | and unobtrusively integrated into any application or framework that supports 9 | [Connect](https://github.com/senchalabs/connect#readme)-style middleware, including 10 | [Express](https://expressjs.com/). 11 | 12 |
13 | 14 | :seedling: [Tutorial](https://www.passportjs.org/tutorials/password/?utm_source=github&utm_medium=referral&utm_campaign=passport-local&utm_content=nav-tutorial) • 15 | :dart: [How-to](https://www.passportjs.org/howtos/password/?utm_source=github&utm_medium=referral&utm_campaign=passport-local&utm_content=nav-howto) • 16 | :hammer_and_wrench: [API Reference](https://www.passportjs.org/api/passport-local/1.x/?utm_source=github&utm_medium=referral&utm_campaign=passport-local&utm_content=nav-api) • 17 | :heart: [Sponsors](https://www.passportjs.org/sponsors/?utm_source=github&utm_medium=referral&utm_campaign=passport-local&utm_content=nav-sponsors) 18 | 19 |
20 | 21 | --- 22 | 23 |

24 | Advertisement 25 |
26 | 1Password, the only password manager you should trust. Industry-leading security and award winning design. 27 |

28 | 29 | --- 30 | 31 | [![npm](https://img.shields.io/npm/v/passport-local.svg)](https://www.npmjs.com/package/passport-local) 32 | [![build](https://img.shields.io/travis/jaredhanson/passport-local.svg)](https://travis-ci.org/jaredhanson/passport-local) 33 | [![coverage](https://img.shields.io/coveralls/jaredhanson/passport-local.svg)](https://coveralls.io/github/jaredhanson/passport-local) 34 | [...](https://github.com/jaredhanson/passport-local/wiki/Status) 35 | 36 | ## Install 37 | 38 | ```bash 39 | $ npm install passport-local 40 | ``` 41 | 42 | ## Usage 43 | 44 | #### Configure Strategy 45 | 46 | The local authentication strategy authenticates users using a username and 47 | password. The strategy requires a `verify` callback, which accepts these 48 | credentials and calls `done` providing a user. 49 | 50 | ```js 51 | passport.use(new LocalStrategy( 52 | function(username, password, done) { 53 | User.findOne({ username: username }, function (err, user) { 54 | if (err) { return done(err); } 55 | if (!user) { return done(null, false); } 56 | if (!user.verifyPassword(password)) { return done(null, false); } 57 | return done(null, user); 58 | }); 59 | } 60 | )); 61 | ``` 62 | 63 | ##### Available Options 64 | 65 | This strategy takes an optional options hash before the function, e.g. `new LocalStrategy({/* options */, callback})`. 66 | 67 | The available options are: 68 | 69 | * `usernameField` - Optional, defaults to 'username' 70 | * `passwordField` - Optional, defaults to 'password' 71 | 72 | Both fields define the name of the properties in the POST body that are sent to the server. 73 | 74 | #### Parameters 75 | 76 | By default, `LocalStrategy` expects to find credentials in parameters 77 | named username and password. If your site prefers to name these fields 78 | differently, options are available to change the defaults. 79 | 80 | passport.use(new LocalStrategy({ 81 | usernameField: 'email', 82 | passwordField: 'passwd', 83 | session: false 84 | }, 85 | function(username, password, done) { 86 | // ... 87 | } 88 | )); 89 | 90 | When session support is not necessary, it can be safely disabled by 91 | setting the `session` option to false. 92 | 93 | The verify callback can be supplied with the `request` object by setting 94 | the `passReqToCallback` option to true, and changing callback arguments 95 | accordingly. 96 | 97 | passport.use(new LocalStrategy({ 98 | usernameField: 'email', 99 | passwordField: 'passwd', 100 | passReqToCallback: true, 101 | session: false 102 | }, 103 | function(req, username, password, done) { 104 | // request object is now first argument 105 | // ... 106 | } 107 | )); 108 | 109 | #### Authenticate Requests 110 | 111 | Use `passport.authenticate()`, specifying the `'local'` strategy, to 112 | authenticate requests. 113 | 114 | For example, as route middleware in an [Express](http://expressjs.com/) 115 | application: 116 | 117 | ```js 118 | app.post('/login', 119 | passport.authenticate('local', { failureRedirect: '/login' }), 120 | function(req, res) { 121 | res.redirect('/'); 122 | }); 123 | ``` 124 | 125 | ## Examples 126 | 127 | * [express-4.x-local-example](https://github.com/passport/express-4.x-local-example) 128 | 129 | Illustrates how to use the password strategy within an [Express](https://expressjs.com) 130 | application. 131 | 132 | Additional examples can be found on the [wiki](https://github.com/jaredhanson/passport-local/wiki/Examples). 133 | 134 | ## License 135 | 136 | [The MIT License](http://opensource.org/licenses/MIT) 137 | 138 | Copyright (c) 2011-2015 Jared Hanson <[http://jaredhanson.net/](http://jaredhanson.net/)> 139 | -------------------------------------------------------------------------------- /etc/conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["plugins/markdown"] 3 | } 4 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The `passport-local` module provides a {@link https://www.passportjs.org/ Passport} 3 | * strategy for authenticating a username and password. 4 | * 5 | * @module passport-local 6 | */ 7 | 8 | 9 | // Module dependencies. 10 | var Strategy = require('./strategy'); 11 | 12 | /* 13 | * `{@link Strategy}` constructor. 14 | * 15 | * @type {function} 16 | */ 17 | exports = module.exports = Strategy; 18 | 19 | /* 20 | * `{@link Strategy}` constructor. 21 | * 22 | * @type {function} 23 | */ 24 | exports.Strategy = Strategy; 25 | -------------------------------------------------------------------------------- /lib/strategy.js: -------------------------------------------------------------------------------- 1 | // Module dependencies. 2 | var passport = require('passport-strategy') 3 | , util = require('util') 4 | , lookup = require('./utils').lookup; 5 | 6 | /** 7 | * Create a new `Strategy` object. 8 | * 9 | * @classdesc This `Strategy` authenticates requests that carry a username and 10 | * password in the body of the request. These credentials are typically 11 | * submitted by the user via an HTML form. 12 | * 13 | * @public 14 | * @class 15 | * @augments base.Strategy 16 | * @param {Object} [options] 17 | * @param {string} [options.usernameField='username'] - Form field name where 18 | * the username is found. 19 | * @param {string} [options.passwordField='password'] - Form field name where 20 | * the password is found. 21 | * @param {boolean} [options.passReqToCallback=false] - When `true`, the 22 | * `verify` function receives the request object as the first argument, 23 | * in accordance with `{@link Strategy~verifyWithReqFn}`. 24 | * @param {Strategy~verifyFn|Strategy~verifyWithReqFn} verify - Function which 25 | * verifies username and password. 26 | * 27 | * @example 28 | * var LocalStrategy = require('passport-local').Strategy; 29 | * 30 | * new LocalStrategy(function(username, password, cb) { 31 | * users.findOne({ username: username }, function(err, user) { 32 | * if (err) { return cb(err); } 33 | * if (!user) { return cb(null, false, { message: 'Incorrect username or password.' }); } 34 | * 35 | * crypto.pbkdf2(password, user.salt, 310000, 32, 'sha256', function(err, hashedPassword) { 36 | * if (err) { return cb(err); } 37 | * if (!crypto.timingSafeEqual(user.hashedPassword, hashedPassword)) { 38 | * return cb(null, false, { message: 'Incorrect username or password.' }); 39 | * } 40 | * return cb(null, user); 41 | * }); 42 | * }); 43 | * }); 44 | * 45 | * @example Construct strategy using top-level export. 46 | * var LocalStrategy = require('passport-local'); 47 | * 48 | * new LocalStrategy(function(username, password, cb) { 49 | * // ... 50 | * }); 51 | */ 52 | function Strategy(options, verify) { 53 | if (typeof options == 'function') { 54 | verify = options; 55 | options = {}; 56 | } 57 | if (!verify) { throw new TypeError('LocalStrategy requires a verify callback'); } 58 | 59 | this._usernameField = options.usernameField || 'username'; 60 | this._passwordField = options.passwordField || 'password'; 61 | 62 | passport.Strategy.call(this); 63 | 64 | /** The name of the strategy, which is set to `'local'`. 65 | * 66 | * @type {string} 67 | * @readonly 68 | */ 69 | this.name = 'local'; 70 | this._verify = verify; 71 | this._passReqToCallback = options.passReqToCallback; 72 | } 73 | 74 | // Inherit from `passport.Strategy`. 75 | util.inherits(Strategy, passport.Strategy); 76 | 77 | /** 78 | * Authenticate request by verifying username and password. 79 | * 80 | * This function is protected, and should not be called directly. Instead, 81 | * use `passport.authenticate()` middleware and specify the {@link Strategy#name `name`} 82 | * of this strategy and any options. 83 | * 84 | * @protected 85 | * @param {http.IncomingMessage} req - The Node.js {@link https://nodejs.org/api/http.html#class-httpincomingmessage `IncomingMessage`} 86 | * object. 87 | * @param {Object} [options] 88 | * @param {string} [options.badRequestMessage='Missing credentials'] - Message 89 | * to display when a request does not include a username or password. 90 | * Used in conjunction with `failureMessage` or `failureFlash` options. 91 | * 92 | * @example 93 | * passport.authenticate('local'); 94 | */ 95 | Strategy.prototype.authenticate = function(req, options) { 96 | options = options || {}; 97 | var username = lookup(req.body, this._usernameField) || lookup(req.query, this._usernameField); 98 | var password = lookup(req.body, this._passwordField) || lookup(req.query, this._passwordField); 99 | 100 | if (!username || !password) { 101 | return this.fail({ message: options.badRequestMessage || 'Missing credentials' }, 400); 102 | } 103 | 104 | var self = this; 105 | 106 | function verified(err, user, info) { 107 | if (err) { return self.error(err); } 108 | if (!user) { return self.fail(info); } 109 | self.success(user, info); 110 | } 111 | 112 | try { 113 | if (self._passReqToCallback) { 114 | this._verify(req, username, password, verified); 115 | } else { 116 | this._verify(username, password, verified); 117 | } 118 | } catch (ex) { 119 | return self.error(ex); 120 | } 121 | }; 122 | 123 | // Export `Strategy`. 124 | module.exports = Strategy; 125 | 126 | 127 | /** 128 | * Verifies `username` and `password` and yields authenticated user. 129 | * 130 | * This function is called by `{@link Strategy}` to verify a username and 131 | * password, and must invoke `cb` to yield the result. 132 | * 133 | * @callback Strategy~verifyFn 134 | * @param {string} username - The username received in the request. 135 | * @param {string} password - The passport received in the request. 136 | * @param {function} cb 137 | * @param {?Error} cb.err - An `Error` if an error occured; otherwise `null`. 138 | * @param {Object|boolean} cb.user - An `Object` representing the authenticated 139 | * user if verification was successful; otherwise `false`. 140 | * @param {Object} cb.info - Additional application-specific context that will be 141 | * passed through for further request processing. 142 | */ 143 | 144 | /** 145 | * Verifies `username` and `password` and yields authenticated user. 146 | * 147 | * This function is called by `{@link Strategy}` to verify a username and 148 | * password when the `passReqToCallback` option is set, and must invoke `cb` to 149 | * yield the result. 150 | * 151 | * @callback Strategy~verifyWithReqFn 152 | * @param {http.IncomingMessage} req - The Node.js {@link https://nodejs.org/api/http.html#class-httpincomingmessage `IncomingMessage`} 153 | * object. 154 | * @param {string} username - The username received in the request. 155 | * @param {string} password - The passport received in the request. 156 | * @param {function} cb 157 | * @param {?Error} cb.err - An `Error` if an error occured; otherwise `null`. 158 | * @param {Object|boolean} cb.user - An `Object` representing the authenticated 159 | * user if verification was successful; otherwise `false`. 160 | * @param {Object} cb.info - Additional application-specific context that will be 161 | * passed through for further request processing. 162 | */ 163 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | exports.lookup = function(obj, field) { 2 | if (!obj) { return null; } 3 | var chain = field.split(']').join('').split('['); 4 | for (var i = 0, len = chain.length; i < len; i++) { 5 | var prop = obj[chain[i]]; 6 | if (typeof(prop) === 'undefined') { return null; } 7 | if (typeof(prop) !== 'object') { return prop; } 8 | obj = prop; 9 | } 10 | return null; 11 | }; 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "passport-local", 3 | "version": "1.0.0", 4 | "description": "Local username and password authentication strategy for Passport.", 5 | "keywords": [ 6 | "passport", 7 | "local", 8 | "auth", 9 | "authn", 10 | "authentication", 11 | "username", 12 | "password" 13 | ], 14 | "author": { 15 | "name": "Jared Hanson", 16 | "email": "jaredhanson@gmail.com", 17 | "url": "http://www.jaredhanson.net/" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git://github.com/jaredhanson/passport-local.git" 22 | }, 23 | "bugs": { 24 | "url": "http://github.com/jaredhanson/passport-local/issues" 25 | }, 26 | "funding": { 27 | "type": "github", 28 | "url": "https://github.com/sponsors/jaredhanson" 29 | }, 30 | "license": "MIT", 31 | "licenses": [ 32 | { 33 | "type": "MIT", 34 | "url": "http://www.opensource.org/licenses/MIT" 35 | } 36 | ], 37 | "main": "./lib", 38 | "dependencies": { 39 | "passport-strategy": "1.x.x" 40 | }, 41 | "devDependencies": { 42 | "make-node": "0.4.6", 43 | "mocha": "2.x.x", 44 | "chai": "2.x.x", 45 | "chai-passport-strategy": "0.1.x" 46 | }, 47 | "engines": { 48 | "node": ">= 0.4.0" 49 | }, 50 | "scripts": { 51 | "test": "make test" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/bootstrap/node.js: -------------------------------------------------------------------------------- 1 | var chai = require('chai'); 2 | 3 | chai.use(require('chai-passport-strategy')); 4 | 5 | global.expect = chai.expect; 6 | -------------------------------------------------------------------------------- /test/package.test.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, expect */ 2 | 3 | var strategy = require('..'); 4 | 5 | describe('passport-local', function() { 6 | 7 | it('should export Strategy constructor directly from package', function() { 8 | expect(strategy).to.be.a('function'); 9 | expect(strategy).to.equal(strategy.Strategy); 10 | }); 11 | 12 | }); 13 | -------------------------------------------------------------------------------- /test/strategy.error.test.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, expect, before */ 2 | 3 | var chai = require('chai') 4 | , Strategy = require('../lib/strategy'); 5 | 6 | 7 | describe('Strategy', function() { 8 | 9 | describe('encountering an error during verification', function() { 10 | var strategy = new Strategy(function(username, password, done) { 11 | done(new Error('something went wrong')); 12 | }); 13 | 14 | var err; 15 | 16 | before(function(done) { 17 | chai.passport(strategy) 18 | .error(function(e) { 19 | err = e; 20 | done(); 21 | }) 22 | .req(function(req) { 23 | req.body = {}; 24 | req.body.username = 'johndoe'; 25 | req.body.password = 'secret'; 26 | }) 27 | .authenticate(); 28 | }); 29 | 30 | it('should error', function() { 31 | expect(err).to.be.an.instanceof(Error); 32 | expect(err.message).to.equal('something went wrong'); 33 | }); 34 | }); 35 | 36 | describe('encountering an exception during verification', function() { 37 | var strategy = new Strategy(function(username, password, done) { 38 | throw new Error('something went horribly wrong'); 39 | }); 40 | 41 | var err; 42 | 43 | before(function(done) { 44 | chai.passport(strategy) 45 | .error(function(e) { 46 | err = e; 47 | done(); 48 | }) 49 | .req(function(req) { 50 | req.body = {}; 51 | req.body.username = 'johndoe'; 52 | req.body.password = 'secret'; 53 | }) 54 | .authenticate(); 55 | }); 56 | 57 | it('should error', function() { 58 | expect(err).to.be.an.instanceof(Error); 59 | expect(err.message).to.equal('something went horribly wrong'); 60 | }); 61 | }); 62 | 63 | }); 64 | -------------------------------------------------------------------------------- /test/strategy.fail.test.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, expect, before */ 2 | /* jshint expr: true */ 3 | 4 | var chai = require('chai') 5 | , Strategy = require('../lib/strategy'); 6 | 7 | 8 | describe('Strategy', function() { 9 | 10 | describe('failing authentication', function() { 11 | var strategy = new Strategy(function(username, password, done) { 12 | return done(null, false); 13 | }); 14 | 15 | var info; 16 | 17 | before(function(done) { 18 | chai.passport(strategy) 19 | .fail(function(i) { 20 | info = i; 21 | done(); 22 | }) 23 | .req(function(req) { 24 | req.body = {}; 25 | req.body.username = 'johndoe'; 26 | req.body.password = 'secret'; 27 | }) 28 | .authenticate(); 29 | }); 30 | 31 | it('should fail', function() { 32 | expect(info).to.be.undefined; 33 | }); 34 | }); 35 | 36 | describe('failing authentication with info', function() { 37 | var strategy = new Strategy(function(username, password, done) { 38 | return done(null, false, { message: 'authentication failed' }); 39 | }); 40 | 41 | var info; 42 | 43 | before(function(done) { 44 | chai.passport(strategy) 45 | .fail(function(i) { 46 | info = i; 47 | done(); 48 | }) 49 | .req(function(req) { 50 | req.body = {}; 51 | req.body.username = 'johndoe'; 52 | req.body.password = 'secret'; 53 | }) 54 | .authenticate(); 55 | }); 56 | 57 | it('should fail', function() { 58 | expect(info).to.be.an('object'); 59 | expect(info.message).to.equal('authentication failed'); 60 | }); 61 | }); 62 | 63 | }); 64 | -------------------------------------------------------------------------------- /test/strategy.fields.test.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, expect, before */ 2 | /* jshint expr: true */ 3 | 4 | var chai = require('chai') 5 | , Strategy = require('../lib/strategy'); 6 | 7 | 8 | describe('Strategy', function() { 9 | 10 | describe('handling a request with valid credentials in body using custom field names', function() { 11 | var strategy = new Strategy({ usernameField: 'userid', passwordField: 'passwd' }, function(username, password, done) { 12 | if (username == 'johndoe' && password == 'secret') { 13 | return done(null, { id: '1234' }, { scope: 'read' }); 14 | } 15 | return done(null, false); 16 | }); 17 | 18 | var user 19 | , info; 20 | 21 | before(function(done) { 22 | chai.passport(strategy) 23 | .success(function(u, i) { 24 | user = u; 25 | info = i; 26 | done(); 27 | }) 28 | .req(function(req) { 29 | req.body = {}; 30 | req.body.userid = 'johndoe'; 31 | req.body.passwd = 'secret'; 32 | }) 33 | .authenticate(); 34 | }); 35 | 36 | it('should supply user', function() { 37 | expect(user).to.be.an.object; 38 | expect(user.id).to.equal('1234'); 39 | }); 40 | 41 | it('should supply info', function() { 42 | expect(info).to.be.an.object; 43 | expect(info.scope).to.equal('read'); 44 | }); 45 | }); 46 | 47 | describe('handling a request with valid credentials in body using custom field names with object notation', function() { 48 | var strategy = new Strategy({ usernameField: 'user[username]', passwordField: 'user[password]' }, function(username, password, done) { 49 | if (username == 'johndoe' && password == 'secret') { 50 | return done(null, { id: '1234' }, { scope: 'read' }); 51 | } 52 | return done(null, false); 53 | }); 54 | 55 | var user 56 | , info; 57 | 58 | before(function(done) { 59 | chai.passport(strategy) 60 | .success(function(u, i) { 61 | user = u; 62 | info = i; 63 | done(); 64 | }) 65 | .req(function(req) { 66 | req.body = {}; 67 | req.body.user = {}; 68 | req.body.user.username = 'johndoe'; 69 | req.body.user.password = 'secret'; 70 | }) 71 | .authenticate(); 72 | }); 73 | 74 | it('should supply user', function() { 75 | expect(user).to.be.an.object; 76 | expect(user.id).to.equal('1234'); 77 | }); 78 | 79 | it('should supply info', function() { 80 | expect(info).to.be.an.object; 81 | expect(info.scope).to.equal('read'); 82 | }); 83 | }); 84 | 85 | }); 86 | -------------------------------------------------------------------------------- /test/strategy.normal.test.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, expect, before */ 2 | /* jshint expr: true */ 3 | 4 | var chai = require('chai') 5 | , Strategy = require('../lib/strategy'); 6 | 7 | 8 | describe('Strategy', function() { 9 | 10 | describe('handling a request with valid credentials in body', function() { 11 | var strategy = new Strategy(function(username, password, done) { 12 | if (username == 'johndoe' && password == 'secret') { 13 | return done(null, { id: '1234' }, { scope: 'read' }); 14 | } 15 | return done(null, false); 16 | }); 17 | 18 | var user 19 | , info; 20 | 21 | before(function(done) { 22 | chai.passport(strategy) 23 | .success(function(u, i) { 24 | user = u; 25 | info = i; 26 | done(); 27 | }) 28 | .req(function(req) { 29 | req.body = {}; 30 | req.body.username = 'johndoe'; 31 | req.body.password = 'secret'; 32 | }) 33 | .authenticate(); 34 | }); 35 | 36 | it('should supply user', function() { 37 | expect(user).to.be.an.object; 38 | expect(user.id).to.equal('1234'); 39 | }); 40 | 41 | it('should supply info', function() { 42 | expect(info).to.be.an.object; 43 | expect(info.scope).to.equal('read'); 44 | }); 45 | }); 46 | 47 | describe('handling a request with valid credentials in query', function() { 48 | var strategy = new Strategy(function(username, password, done) { 49 | if (username == 'johndoe' && password == 'secret') { 50 | return done(null, { id: '1234' }, { scope: 'read' }); 51 | } 52 | return done(null, false); 53 | }); 54 | 55 | var user 56 | , info; 57 | 58 | before(function(done) { 59 | chai.passport(strategy) 60 | .success(function(u, i) { 61 | user = u; 62 | info = i; 63 | done(); 64 | }) 65 | .req(function(req) { 66 | req.query = {}; 67 | req.query.username = 'johndoe'; 68 | req.query.password = 'secret'; 69 | }) 70 | .authenticate(); 71 | }); 72 | 73 | it('should supply user', function() { 74 | expect(user).to.be.an.object; 75 | expect(user.id).to.equal('1234'); 76 | }); 77 | 78 | it('should supply info', function() { 79 | expect(info).to.be.an.object; 80 | expect(info.scope).to.equal('read'); 81 | }); 82 | }); 83 | 84 | describe('handling a request without a body', function() { 85 | var strategy = new Strategy(function(username, password, done) { 86 | throw new Error('should not be called'); 87 | }); 88 | 89 | var info, status; 90 | 91 | before(function(done) { 92 | chai.passport(strategy) 93 | .fail(function(i, s) { 94 | info = i; 95 | status = s; 96 | done(); 97 | }) 98 | .authenticate(); 99 | }); 100 | 101 | it('should fail with info and status', function() { 102 | expect(info).to.be.an.object; 103 | expect(info.message).to.equal('Missing credentials'); 104 | expect(status).to.equal(400); 105 | }); 106 | }); 107 | 108 | describe('handling a request without a body, but no username and password', function() { 109 | var strategy = new Strategy(function(username, password, done) { 110 | throw new Error('should not be called'); 111 | }); 112 | 113 | var info, status; 114 | 115 | before(function(done) { 116 | chai.passport(strategy) 117 | .fail(function(i, s) { 118 | info = i; 119 | status = s; 120 | done(); 121 | }) 122 | .req(function(req) { 123 | req.body = {}; 124 | }) 125 | .authenticate(); 126 | }); 127 | 128 | it('should fail with info and status', function() { 129 | expect(info).to.be.an.object; 130 | expect(info.message).to.equal('Missing credentials'); 131 | expect(status).to.equal(400); 132 | }); 133 | }); 134 | 135 | describe('handling a request without a body, but no password', function() { 136 | var strategy = new Strategy(function(username, password, done) { 137 | throw new Error('should not be called'); 138 | }); 139 | 140 | var info, status; 141 | 142 | before(function(done) { 143 | chai.passport(strategy) 144 | .fail(function(i, s) { 145 | info = i; 146 | status = s; 147 | done(); 148 | }) 149 | .req(function(req) { 150 | req.body = {}; 151 | req.body.username = 'johndoe'; 152 | }) 153 | .authenticate(); 154 | }); 155 | 156 | it('should fail with info and status', function() { 157 | expect(info).to.be.an.object; 158 | expect(info.message).to.equal('Missing credentials'); 159 | expect(status).to.equal(400); 160 | }); 161 | }); 162 | 163 | describe('handling a request without a body, but no username', function() { 164 | var strategy = new Strategy(function(username, password, done) { 165 | throw new Error('should not be called'); 166 | }); 167 | 168 | var info, status; 169 | 170 | before(function(done) { 171 | chai.passport(strategy) 172 | .fail(function(i, s) { 173 | info = i; 174 | status = s; 175 | done(); 176 | }) 177 | .req(function(req) { 178 | req.body = {}; 179 | req.body.password = 'secret'; 180 | }) 181 | .authenticate(); 182 | }); 183 | 184 | it('should fail with info and status', function() { 185 | expect(info).to.be.an.object; 186 | expect(info.message).to.equal('Missing credentials'); 187 | expect(status).to.equal(400); 188 | }); 189 | }); 190 | 191 | }); 192 | -------------------------------------------------------------------------------- /test/strategy.options.test.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, expect, before */ 2 | /* jshint expr: true */ 3 | 4 | var chai = require('chai') 5 | , Strategy = require('../lib/strategy'); 6 | 7 | 8 | describe('Strategy', function() { 9 | 10 | describe('handling a request without a body, but no username and password, with message option to authenticate', function() { 11 | var strategy = new Strategy(function(username, password, done) { 12 | throw new Error('should not be called'); 13 | }); 14 | 15 | var info, status; 16 | 17 | before(function(done) { 18 | chai.passport(strategy) 19 | .fail(function(i, s) { 20 | info = i; 21 | status = s; 22 | done(); 23 | }) 24 | .req(function(req) { 25 | req.body = {}; 26 | }) 27 | .authenticate({ badRequestMessage: 'Something is wrong with this request' }); 28 | }); 29 | 30 | it('should fail with info and status', function() { 31 | expect(info).to.be.an.object; 32 | expect(info.message).to.equal('Something is wrong with this request'); 33 | expect(status).to.equal(400); 34 | }); 35 | }); 36 | 37 | }); 38 | -------------------------------------------------------------------------------- /test/strategy.passreq.test.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, expect, before */ 2 | /* jshint expr: true */ 3 | 4 | var chai = require('chai') 5 | , Strategy = require('../lib/strategy'); 6 | 7 | 8 | describe('Strategy', function() { 9 | 10 | describe('passing request to verify callback', function() { 11 | var strategy = new Strategy({passReqToCallback: true}, function(req, username, password, done) { 12 | if (username == 'johndoe' && password == 'secret') { 13 | return done(null, { id: '1234' }, { scope: 'read', foo: req.headers['x-foo'] }); 14 | } 15 | return done(null, false); 16 | }); 17 | 18 | var user 19 | , info; 20 | 21 | before(function(done) { 22 | chai.passport(strategy) 23 | .success(function(u, i) { 24 | user = u; 25 | info = i; 26 | done(); 27 | }) 28 | .req(function(req) { 29 | req.headers['x-foo'] = 'hello'; 30 | 31 | req.body = {}; 32 | req.body.username = 'johndoe'; 33 | req.body.password = 'secret'; 34 | }) 35 | .authenticate(); 36 | }); 37 | 38 | it('should supply user', function() { 39 | expect(user).to.be.an.object; 40 | expect(user.id).to.equal('1234'); 41 | }); 42 | 43 | it('should supply info', function() { 44 | expect(info).to.be.an.object; 45 | expect(info.scope).to.equal('read'); 46 | }); 47 | 48 | it('should supply request header in info', function() { 49 | expect(info.foo).to.equal('hello'); 50 | }); 51 | }); 52 | 53 | }); 54 | -------------------------------------------------------------------------------- /test/strategy.test.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, expect */ 2 | 3 | var Strategy = require('../lib/strategy'); 4 | 5 | 6 | describe('Strategy', function() { 7 | 8 | var strategy = new Strategy(function(){}); 9 | 10 | it('should be named local', function() { 11 | expect(strategy.name).to.equal('local'); 12 | }); 13 | 14 | it('should throw if constructed without a verify callback', function() { 15 | expect(function() { 16 | var s = new Strategy(); 17 | }).to.throw(TypeError, 'LocalStrategy requires a verify callback'); 18 | }); 19 | 20 | }); 21 | --------------------------------------------------------------------------------