CouchDB Authentication Without Server-Side Code

This is a guest post by community member Eirik Brandtzæg.

The powerful REST API in CouchDB makes building client-side only web applications a breeze.
It’s also possible to add security by requiring users to authenticate against the API. Here we will discuss how to authenticate against the API client-side, or via nginx, without any server-side code.

Enable authentication

Enable authentication by setting require_valid_user to true, located under Configuration > Main config > chttpd. With the setting enabled every request to CouchDB must either contain a valid Authentication or Cookie header, a simple yet effective security mechanism.

Client-side authentication

The best way for a client to login is to retrieve a cookie, which is done by making a POST against /_session with name and password in body, like this:
(note; won’t work)

POST /_session
Content-Type: application/json

{"name":"admin","password":"admin"}

However, it’s a bit more challenging, because the request making the POST must also include a valid Authroization or Cookie header for the user we want to authenticate.
The only way to properly receive a Cookie is to include the Authorization header, so the request using Basic authentication must look like this:

POST /_session
Content-Type: application/json
Authorization: Basic YWRtaW46YWRtaW4=

{"name":"admin","password":"admin"}

With curl this could be achieved by the following command curl http://admin:admin@localhost:5984/_session -H 'Content-Type: application/json' -d '{"name":"admin","password":"admin"}'.

In a client-side web application we can achieve this by appending the header to the request, like this:

fetch('/_session', {
  method: 'POST',
  credentials: 'include',
  headers: {
    'content-type': 'application/json',
    authorization: `Basic ${btoa('admin:admin')}`
  },
  body: JSON.stringify({name: 'admin', password: 'admin'})
})

Now every subsequent request only need to include credentials: 'include'.
This solution also works cross-domain, by enabling CORS under Configuration > CORS, even with All domains (*) as origin.
It’s also possible to do all requests using the Authorization header, but the Cookie-approach is much cleaner and safer.

Project Fauxton

One of the immediate drawbacks of requiring valid users is that /_utils (Project Fauxton) is essentially unreachable, as the login-form is also locked down.

Logging in via the client-side approach above is possible, if the web application is hosted on the same origin (domain) as CouchDB, or by running the above fetch-code directly in the browser DevTools console.

nginx and proxy_pass

Another more sleek solution is to add nginx as a proxy, and render a custom login-form when CouchDB requires authentication. Any other proxy/gateway can also be used.

We can set nginx to proxy all requests to CouchDB, and tell it to intercept all errors. When intercepting errors nginx will show its own error pages, and then we can create our own 401 page, which is a login form.
Creating a custom path, e.g., /login, is also possible.
The config could look like this:

server {
  listen 80;
  
  location ~ 401.html$ {
    alias /usr/share/nginx/html/couchdb/login.html;
  }

  location / {
    error_page 401 /401.html;
    proxy_intercept_errors on;
    proxy_pass http://172.17.0.1:5984;
  }
}

Then we can make a custom login form as login.html.
Note, normal form with action won’t work, again because of the required Authorization header, but we can use the JavaScript snippet from above to bypass this:

<!doctype html>
<title>LOGIN!</title>
<form id="form">
  <input id="username" placeholder="name">
  <input id="password" placeholder="password" type="password">
  <button type="submit">LOGIN!</button>
  <p id="output"></p>

  <a href="/_utils">Go to Project Fauxton</a>
</form>
<script>
  form.addEventListener('submit', e => {
    e.preventDefault();
    const data = {name: username.value, password: password.value};
    output.innerText = '';
    fetch('/_session', {
      method: 'POST',
      credentials: 'include',
      headers: {
        'content-type': 'application/json', 
        authorization: `Basic ${btoa(data.name + ':' + data.password)}`},
      body: JSON.stringify(data)
    }).then(res => res.text()).then(res => output.innerText = res);
  });
</script>

CouchDB Weekly News, February 1, 2018

Releases in the PouchDB Universe

  • ember-pouch 5.0.0 – Ember Pouch is a PouchDB/CouchDB adapter for Ember Data 2.0+.
  • rxdb 7.3.2 – A reactive Database for Progressive Web Apps and more

Opinions and other News in the CouchDB Universe

… and in the PouchDB Universe

CouchDB Use Cases, Questions and Answers

Use Case:

  • Cayley, an open-source graph database, now has a CouchDB/PouchDB back-end. The PouchDB back-end works in the browser.

Stack Overflow:

no public answer yet:

PouchDB Use Cases, Questions and Answers

Stack Overflow:

For more new questions and answers about CouchDB, see these search results and about PouchDB, see these.

Get involved!

If you want to get into working on CouchDB:

  • We have an infinite number of open contributor positions on CouchDB. Submit a pull request and join the project!
  • Do you want to help us with the work on the new CouchDB website? Get in touch on our new website mailing list and join the website team! – www@couchdb.apache.org
  • The CouchDB advocate marketing programme is just getting started. Join us in CouchDB’s Advocate Hub!
  • CouchDB has a new wiki. Help us move content from the old to the new one!
  • Can you help with Web Design, Development or UX for our Admin Console? No Erlang skills required! – Get in touch with us.
  • Do you want to help moving the CouchDB docs translation forward? We’d love to have you in our L10n team! See our current status and languages we’d like to provide CouchDB docs in on this page. If you’d like to help, don’t hesitate to contact the L10n mailing list on l10n@couchdb.apache.org or ping Andy Wenk (awenkhh on IRC).

We’d be happy to welcome you on board!

Events

Job opportunities for people with CouchDB skills

Also in the news

Submit news to the CouchDB Weekly

Reach out to us with your news suggestions by sending us an email or by contacting us on Twitter @CouchDB.