9.2.12. Authentication

Interfaces for obtaining session and authorization data.

Note

We’re also strongly recommend you to setup SSL to improve all authentication methods security.

Basic Authentication

Basic authentication (RFC 2617) is a quick and simple way to authenticate with CouchDB. The main drawback is the need to send user credentials with each request which may be insecure and could hurt operation performance (since CouchDB must compute password hash with every request):

Request:

GET / HTTP/1.1
Accept: application/json
Authorization: Basic cm9vdDpyZWxheA==
Host: localhost:5984

Response:

HTTP/1.1 200 OK
Cache-Control: must-revalidate
Content-Length: 177
Content-Type: application/json
Date: Mon, 03 Dec 2012 00:44:47 GMT
Server: CouchDB (Erlang/OTP)

{
  "couchdb":"Welcome",
  "uuid":"0a959b9b8227188afc2ac26ccdf345a6",
  "version":"1.3.0",
  "vendor": {
    "version":"1.3.0",
    "name":"The Apache Software Foundation"
  }
}

Proxy Authentication

Note

To use this authentication method make sure that the {couch_httpd_auth, proxy_authentication_handler} value in added to the list of the active httpd/authentication_handlers:

[httpd]
authentication_handlers = {couch_httpd_oauth, oauth_authentication_handler}, {couch_httpd_auth, cookie_authentication_handler}, {couch_httpd_auth, proxy_authentication_handler}, {couch_httpd_auth, default_authentication_handler}

Proxy authentication is very useful in case your application already uses some external authentication service and you don’t want to duplicate users and their roles in CouchDB.

This authentication method allows creation of a User Context Object for remotely authenticated user. By default, the client just need to pass specific headers to CouchDB with related request:

Request:

GET /_session HTTP/1.1
Host: localhost:5984
Accept: application/json
Content-Type: application/json; charset=utf-8
X-Auth-CouchDB-Roles: users,blogger
X-Auth-CouchDB-UserName: foo

Response:

HTTP/1.1 200 OK
Cache-Control: must-revalidate
Content-Length: 190
Content-Type: application/json
Date: Fri, 14 Jun 2013 10:16:03 GMT
Server: CouchDB (Erlang/OTP)

{
    "info": {
        "authenticated": "proxy",
        "authentication_db": "_users",
        "authentication_handlers": [
            "oauth",
            "cookie",
            "proxy",
            "default"
        ]
    },
    "ok": true,
    "userCtx": {
        "name": "foo",
        "roles": [
            "users",
            "blogger"
        ]
    }
}

Note that you don’t need to request session to be authenticated by this method if all required HTTP headers are provided.

OAuth Authentication

CouchDB supports OAuth 1.0 authentication (RFC 5849). OAuth provides a method for clients to access server resources without sharing real credentials (username and password).

First, configure oauth, by setting consumer and token with their secrets and binding token to real CouchDB username.

Probably, it’s not good idea to work with plain curl, let use some scripting language like Python:

#!/usr/bin/env python2
from oauth import oauth # pip install oauth
import httplib

URL = 'http://localhost:5984/_session'
CONSUMER_KEY = 'consumer1'
CONSUMER_SECRET = 'sekr1t'
TOKEN = 'token1'
SECRET = 'tokensekr1t'

consumer = oauth.OAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET)
token = oauth.OAuthToken(TOKEN, SECRET)
req = oauth.OAuthRequest.from_consumer_and_token(
    consumer,
    token=token,
    http_method='GET',
    http_url=URL,
    parameters={}
)
req.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(), consumer,token)

headers = req.to_header()
headers['Accept'] = 'application/json'

con = httplib.HTTPConnection('localhost', 5984)
con.request('GET', URL, headers=headers)
resp = con.getresponse()
print resp.read()

or Ruby:

#!/usr/bin/env ruby

require 'oauth' # gem install oauth

URL = 'http://localhost:5984'
CONSUMER_KEY = 'consumer1'
CONSUMER_SECRET = 'sekr1t'
TOKEN = 'token1'
SECRET = 'tokensekr1t'

@consumer = OAuth::Consumer.new CONSUMER_KEY,
                                CONSUMER_SECRET,
                                {:site => URL}

@access_token = OAuth::AccessToken.new(@consumer, TOKEN, SECRET)

puts @access_token.get('/_session').body

Both snippets produces similar request and response pair:

GET /_session HTTP/1.1
Host: localhost:5984
Accept: application/json
Authorization: OAuth realm="", oauth_nonce="81430018", oauth_timestamp="1374561749", oauth_consumer_key="consumer1", oauth_signature_method="HMAC-SHA1", oauth_version="1.0", oauth_token="token1", oauth_signature="o4FqJ8%2B9IzUpXH%2Bk4rgnv7L6eTY%3D"
HTTP/1.1 200 OK
Cache-Control : must-revalidate
Content-Length : 167
Content-Type : application/json
Date : Tue, 23 Jul 2013 06:51:15 GMT
Server: CouchDB (Erlang/OTP)


{
  "ok": true,
  "info": {
    "authenticated": "oauth",
    "authentication_db": "_users",
    "authentication_handlers": ["oauth", "cookie", "default"]
  },
  "userCtx": {
    "name": "couchdb_username",
    "roles": []
  }
}

There we request the _session resource to ensure that authentication was successful and the target CouchDB username is correct. Change the target URL to request required resource.