When you start out fresh, CouchDB allows any request to be made by anyone.
Create a database? No problem, here you go. Delete some documents? Same deal.
CouchDB calls this the Admin Party. Everybody has privileges to do anything.
Neat.

While it is incredibly easy to get started with CouchDB that way,
it should be obvious that putting a default installation into the wild is
adventurous. Any rogue client could come along and delete a database.

A note of relief: by default, CouchDB will listen only on your loopback
network interface (127.0.0.1 or localhost) and thus only you will be
able to make requests to CouchDB, nobody else. But when you start to open up
your CouchDB to the public (that is, by telling it to bind to your machine’s
public IP address), you will want to think about restricting access so that
the next bad guy doesn’t ruin your admin party.

In our previous discussions, we dropped some keywords about how things
without the Admin Party work. First, there’s admin itself, which implies
some sort of super user. Then there are privileges. Let’s explore these terms
a little more.

CouchDB has the idea of an admin user (e.g. an administrator, a super user,
or root) that is allowed to do anything to a CouchDB installation. By default,
everybody is an admin. If you don’t like that, you can create specific admin
users with a username and password as their credentials.

CouchDB also defines a set of requests that only admin users are allowed to
do. If you have defined one or more specific admin users, CouchDB will ask for
identification for certain requests:

When starting out fresh, we can add a database. Nothing unexpected. Now let’s
create an admin user. We’ll call her anna, and her password is secret.
Note the double quotes in the following code; they are needed to denote a string
value for the configuration API:

Seeing the plain-text password is scary, isn’t it? No worries, CouchDB doesn’t
show the plain-text password anywhere. It gets hashed right away. The hash
is that big, ugly, long string that starts out with -hashed-.
How does that work?

Creates a new 128-bit UUID. This is our salt.

Creates a sha1 hash of the concatenation of the bytes of the plain-text
password and the salt (sha1(password+salt)).

Prefixes the result with -hashed- and appends ,salt.

To compare a plain-text password during authentication with the stored hash,
the same procedure is run and the resulting hash is compared to the stored
hash. The probability of two identical hashes for different passwords is too
insignificant to mention (c.f. Bruce Schneier). Should the stored hash fall
into the hands of an attacker, it is, by current standards, way too inconvenient
(i.e., it’d take a lot of money and time) to find the plain-text password from
the hash.

But what’s with the -hashed- prefix? When CouchDB starts up, it reads a set
of .ini files with config settings. It loads these settings into an internal
data store (not a database). The config API lets you read the current
configuration as well as change it and create new entries. CouchDB is writing
any changes back to the .ini files.

The .ini files can also be edited by hand when CouchDB is not running.
Instead of creating the admin user as we showed previously, you could have
stopped CouchDB, opened your local.ini, added anna=secret to the
admins, and restarted CouchDB. Upon reading the new line from
local.ini, CouchDB would run the hashing algorithm and write back the hash to
local.ini, replacing the plain-text password. To make sure CouchDB only hashes
plain-text passwords and not an existing hash a second time, it prefixes
the hash with -hashed-, to distinguish between plain-text passwords and
hashed passwords. This means your plain-text password can’t start with the
characters -hashed-, but that’s pretty unlikely to begin with.

Note

Since 1.3.0 release CouchDB uses -pbkdf2- prefix
by default to sign about using PBKDF2 hashing algorithm instead of
SHA1.

If you have ever accessed a website or FTP server that was password-protected,
the username:password@ URL variant should look familiar.

If you are security conscious, the missing s in http:// will make you
nervous. We’re sending our password to CouchDB in plain text. This is a bad
thing, right? Yes, but consider our scenario: CouchDB listens on 127.0.0.1
on a development box that we’re the sole user of. Who could possibly sniff our
password?

If you are in a production environment, however, you need to reconsider. Will
your CouchDB instance communicate over a public network? Even a LAN shared
with other collocation customers is public. There are multiple ways to secure
communication between you or your application and CouchDB that exceed the
scope of this documentation. CouchDB as of version 1.1.0
comes with SSL built in.

Basic authentication that uses plain-text passwords is nice and convenient,
but not very secure if no extra measures are taken. It is also a very poor
user experience. If you use basic authentication to identify admins,
your application’s users need to deal with an ugly, unstylable browser modal
dialog that says non-professional at work more than anything else.

To remedy some of these concerns, CouchDB supports cookie authentication.
With cookie authentication your application doesn’t have to include the ugly
login dialog that the users’ browsers come with. You can use a regular HTML
form to submit logins to CouchDB. Upon receipt, CouchDB will generate a
one-time token that the client can use in its next request to CouchDB. When
CouchDB sees the token in a subsequent request, it will authenticate the user
based on the token without the need to see the password again. By default,
a token is valid for 10 minutes.

To obtain the first token and thus authenticate a user for the first time,
the username and password must be sent to the _session
API. The API is smart enough to decode HTML form submissions, so you don’t have
to resort to any smarts in your application.

If you are not using HTML forms to log in, you need to send an HTTP request
that looks as if an HTML form generated it. Luckily, this is super simple:

You can keep using this token for 10 minutes by default. After 10 minutes you
need to authenticate your user again. The token lifetime can be configured
with the timeout (in seconds) setting in the couch_httpd_auth configuration section.

You may already note that CouchDB administrators are defined within the config
file and are wondering if regular users are also stored there. No, they are not.
CouchDB has a special authentication database, named _users by default,
that stores all registered users as JSON documents.

This special database is a system database. This means that while it shares
the common database API, there are some
special security-related constraints applied. Below is a list of how the
authentication database is different from the other databases.

These draconian rules are necessary since CouchDB cares about its users’
personal information and will not disclose it to just anyone. Often, user
documents contain system information like login, password hash and roles,
apart from sensitive personal information like real name, email, phone, special
internal identifications and more. This is not information that you
want to share with the World.

name (string): User’s name aka login. Immutable e.g. you cannot
rename an existing user - you have to create new one

roles (array of string): List of user roles. CouchDB doesn’t provide
any built-in roles, so you’re free to define your own depending on your needs.
However, you cannot set system roles like _admin there. Also, only
administrators may assign roles to users - by default all users have no roles

password_sha (string): Hashed password with salt. Used for simplepassword_scheme

password_scheme (string): Password hashing scheme. May be simple or
pbkdf2

salt (string): Hash salt. Used for simplepassword_scheme

type (string): Document type. Constantly has the value user

Additionally, you may specify any custom fields that relate to the target
user. This is a good place to store user’s private information because only the
target user and CouchDB administrators may browse it.

The reason there is a special prefix before a user’s login name is to have
namespaces that users belong to. This prefix is designed to prevent
replication conflicts when you try merging two or more _user databases.

For current CouchDB releases, all users belong to the same
org.couchdb.user namespace and this cannot be changed. This may be changed
in future releases.

The document was successfully created! The user jan should now exist in our
database. Let’s check if this is true:

curl-XPOSThttp://localhost:5984/_session-d'name=jan&password=apple'

CouchDB should respond with:

{"ok":true,"name":"jan","roles":[]}

This means that the username was recognized and the password’s hash matches
with the stored one. If we specify an incorrect login and/or password, CouchDB
will notify us with the following error message:

Let’s define what is password changing from the point of view of CouchDB and
the authentication database. Since “users” are “documents”, this operation is
just updating the document with a special field password which contains
the plain text password. Scared? No need to be. The authentication database
has a special internal hook on document update which looks for this field and
replaces it with the secured hash depending on the chosen password_scheme.

Summarizing the above process - we need to get the document’s content, add
the password field with the new password in plain text and then store the
JSON result to the authentication database.

Sometimes users want to share some information with the world. For instance,
their contact email to let other users get in touch with them. To solve this
problem, but still keep sensitive and private information secured, there is
a special configuration option public_fields. In this option you may define
a comma-separated list of users document fields that will be publicly available.

Normally, if you request a user document and you’re not an administrator or the
document’s owner, CouchDB will respond with 404 Not Found:

curlhttp://localhost:5984/_users/org.couchdb.user:robert

{"error":"not_found","reason":"missing"}

This response is constant for both cases when user exists or doesn’t exist for
security reasons.

Now let’s share the field name. First, set up the public_fields
configuration option. Remember, that this action requires administrator
privileges. The next command will prompt you for user admin’s password:

Now that you have a few users who can log in, you probably want to set up some
restrictions on what actions they can perform based on their identity and their
roles. Each database on a CouchDB server can contain its own set of
authorization rules that specify which users are allowed to read and write
documents, create design documents, and change certain database configuration
parameters. The authorization rules are set up by a server admin and can be
modified at any time.

Database authorization rules assign a user into one of two classes:

members, who are allowed to read all documents and create and modify any
document except for design documents.

admins, who can read and write all types of documents, modify which users
are members or admins, and set certain per-database configuration options.

Note that a database admin is not the same as a server admin – the actions
of a database admin are restricted to a specific database.

When a database is first created, there are no members or admins. HTTP
requests that have no authentication credentials or have credentials for a
normal user are treated as members, and those with server admin credentials
are treated as database admins. To change the default permissions, you must
create a _security document in the database:

If Jan attempted to create a design doc, however, CouchDB would return a
401 Unauthorized error because the username “jan” is not in the list of
admin names and the /_users/org.couchdb.user:jan document doesn’t contain
a role that matches any of the declared admin roles. If you want to promote
Jan to an admin, you can update the security document to add “jan” to
the names array under admin. Keeping track of individual database
admin usernames is tedious, though, so you would likely prefer to create a
database admin role and assign that role to the org.couchdb.user:jan user
document: