A PouchDB plug-in that simulates CouchDB's authentication daemon. Includes a users db that functions like CouchDB's.
Branch: master
Clone or download
linus 3.0.1, use pouchdb-req-http-query 2.0.0 (#43)
* Require pouchdb-req-http-query 2.0.0
* Supports PouchDB 6.x
Latest commit eaf849d Jun 16, 2017

README.md

pouchdb-auth

Build Status Dependency Status devDependency Status

A PouchDB plug-in that simulates CouchDB's authentication daemon.

Includes a users db that functions like CouchDB's. Also works in the browser.

Usage

# npm install --save pouchdb-auth
var PouchDB = require('pouchdb')
var Auth = require('pouchdb-auth')
PouchDB.plugin(Auth)

var db = new PouchDB('_users')

pouchdb-auth adds 3 methods to the PouchDB API

  1. db.hashAdminPasswords(admins)
  2. db.generateSecret()
  3. db.useAsAuthenticationDB()
  4. db.stopUsingAsAuthenticationDB

db.hashAdminPasswords(admins[, options[, callback]])

admins is an object in the form of 'username': 'password'.

Returns a promise, unless callback is passed. Resolves with object with all values being hashed.

db.hashAdminPasswords({ 'admin': 'secret' }
.then(function (hashed) {
  // hashed.admin now looks like '-pbkdf2-243ba92f8f575c70d3d607b408…21731411301c11cb1d81481f51d1108,10'
})
  • options.iterations: The number of pbkdf2 iterations to use when hashing the passwords. Defaults to CouchDB's 10.

See below ("How it works") for more background information

db.generateSecret()

Generates a secret that you can use for useAsAuthenticationDB(). This is a synchronous method.

db.useAsAuthenticationDB([options[, callback]])

This function transforms the database on which it is called into an authentication database. It does that by installing strict validation rules, making sure passwords are hashed in user documents before they're written into the db, and by adding the following methods to the db (documented below):

  • db.signUp(username, password[, options[, callback]])

  • db.logIn(username, password[, options[, callback]])

  • db.logOut([options[, callback]])

  • db.session([options[, callback]])

  • db.multiUserLogIn([callback])

  • db.multiUserSession([sessionID[, callback]])

  • options.isOnlineAuthDB: If true, password hashing, keeping track of the session and doc validation is all handled by the CouchDB on the other end. Defaults to true if called on an http database, otherwise false. An online db currently doesn't provide the db.multiUser* methods.

  • options.timeout: By default, a session is valid for 600 seconds. If you want to renew the session, call db.session() within this time window, or set the expiration time higher (or to 0, which sets it to infinite), by changing this value.

  • options.secret: To calculate the session keys, a secret is necessary. You can pass in your own using this parameter. Otherwise, a random one is generated for the authentication db.

  • options.admins (optional): Allows to pass in an admins object that looks like the one defined in CouchDB's _config.

  • options.iterations: The number of pbkdf2 iterations to use when hashing the passwords. Defaults to CouchDB's 10.

Returns a promise, unless callback is passed. Resolves with nothing.

db.useAsAuthenticationDB()
.then(function () {
  // db is now ready to be used as users database, with all behavior
  // of CouchDB's `_users` database applied

})

db.stopUsingAsAuthenticationDB()

Removes custom behavior and methods applied by db.useAsAuthenticationDB().

Returns nothing. This is a synchronous method.

db.stopUsingAsAuthenticationDB();

db.signUp(username, password[, options[, callback]])

A small helper function: pretty much equivalent to saving a CouchDB user document with the passed in values in the database using PouchDB.

username and password are both strings and required.

options.roles (optional) is an array of strings with roles names, used for authorizing access to databases, see "How it works" below.

Returns a promise, unless callback is passed. Resolves with put response.

db.signUp('john', 'secret')
.then(function (response) {
  // {
  //   ok: true,
  //   id: 'org.couchdb.user:john',
  //   rev: '1-A6157A5EA545C99B00FF904EEF05FD9F'
  // }
})

db.logIn(username, password[, callback])

Tries to get the user specified by username from the database, if its password (after hashing) matches, the user is considered to be logged in. This fact is then stored in memory, allowing the other methods (db.logOut & db.session) to use it later on.

Returns a promise, unless callback is passed. Resolves with name and roles. If username and/or password is incorrect, rejects with unauthorized error.

db.logIn('john', 'secret')
.then(function (response) {
  // {
  //   ok: true,
  //   name: 'john',
  //   roles: ['roles', 'here']
  // }
});

db.logIn('john', 'wrongsecret')
.catch(function (error) {
  // error.name === `unauthorized`
  // error.status === 401
  // error.message === 'Name or password is incorrect.'
});

db.logOut(callback)

Removes the current session.

Returns a promise that resolves to {ok: true}, to match a CouchDB logout. This method never fails, it works even if there is no session.

db.logOut()
.then(function (resp) {
  // { ok: true }
});

db.session([callback])

Reads the current session from the db.

Returns a promise, unless callback is passed. Note that db.session() does not return an error if the current user has no valid session, just like CouchDB returns a 200 status to a GET /_session request. To determine whether the current user has a valid session or not, check if response.userCtx.name is set.

db.session()
.then(function (response) {
  // {
  //   "ok": true,
  //   "userCtx": {
  //     "name": null,
  //     "roles": [],
  //   },
  //   "info": {
  //     "authentication_handlers": ["api"]
  //   }
  // }
})

db.multiUserLogIn(username, password[, callback])

This works the same as db.logIn(), but returns an extra property (sessionID), so multiple sessions can be managed at the same time. You pass in this property to the db.multiUserSession function as a reminder which session you are talking about.

As a matter of fact, the normal functions are just a small wrapper over the db.multiUser* functions. They just store and re-use the last sessionID internally.

db.multiUserLogIn('john', 'secret')
.then(response) {
  // {
  //   ok: true,
  //   name: 'username',
  //   roles: ['roles', 'here'],
  //   sessionID: 'amFuOjU2Njg4MkI5OkEK3-1SRseo6yNRHfk-mmk6zOxm'
  // }
});

db.multiUserSession(sessionID[, callback])

The same as db.session(), but supporting multiple sessions at the same time. Pass in a sessionID obtained from a db.multiUserLogIn() call. If sessionID is not given, a normal non-logged in session will be returned. A new updated sessionID is generated and included to prevent the session from expiring.

db.multiUserSession('amFuOjU2Njg4MkI5OkEK3-1SRseo6yNRHfk-mmk6zOxm')
.then(response) {
  // {
  //   "ok": true,
  //   "userCtx": {
  //     "name": 'john',
  //     "roles": [],
  //   },
  //   "info": {
  //     "authentication_handlers": ["api"]
  //   },
  //   sessionID: 'some-new-session-id'
  // }
}

db.multiUserLogOut()

Contrary to what you might expect, this method does not exist. Multi user logouts are as simple as just forgetting the sessionID. That is the only thing the db.logOut() method does internally. No other state is kept.

How it works

First, make sure you understand how the _users database works in CouchDB. A good start is the CouchDB documentation on the authentication database

Admin users are not stored in the _users database, but in the [admins] section of couch.ini, see http://docs.couchdb.org/en/latest/config/auth.html

When setting passwords clear text, CouchDB will automatically overwrite them with hashed passwords on restart. the hashAdminPasswords function can be used to emulate that behaviour with PouchDB-Auth.

The roles property of _users documents is used by CouchDB to determine access to databases, which can be set in the _security setting of each database. There are now default roles by CouchDB, so you are free to set your own (With the excepion of system roles starting with a _). The roles property can only be changed by CouchDB admin users. More on authorization in CouchDB: http://docs.couchdb.org/en/latest/intro/security.html#authorization

License

Apache-2.0