.. Licensed under the Apache License, Version 2.0 (the "License"); you may not
.. use this file except in compliance with the License. You may obtain a copy of
.. the License at
..
..   http://www.apache.org/licenses/LICENSE-2.0
..
.. Unless required by applicable law or agreed to in writing, software
.. distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
.. WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
.. License for the specific language governing permissions and limitations under
.. the License.

.. _api/auth:

==============
Authentication
==============

Interfaces for obtaining session and authorization data.

.. note:: We're also strongly recommend you to
   :ref:`setup SSL <config/ssl>` to improve all authentication methods security.


.. _api/auth/basic:

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**:

.. code-block:: http

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

**Response**:

.. code-block:: http

    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"
      }
    }

.. _Basic authentication: http://en.wikipedia.org/wiki/Basic_access_authentication


.. _api/auth/cookie:

Cookie Authentication
=====================

For cookie authentication (:rfc:`2109`) CouchDB generates a token that the
client can use for the next few requests to CouchDB. Tokens are valid until
a timeout. When CouchDB sees a valid token in a subsequent request, it will
authenticate user by this token without requesting the password again. By
default, cookies are valid for 10 minutes, but it's :config:option:`adjustable
<couch_httpd_auth/timeout>`. Also it's possible to make cookies
:config:option:`persistent <couch_httpd_auth/allow_persistent_cookies>`

To obtain the first token and thus authenticate a user for the first time, the
`username` and `password` must be sent to the :ref:`_session API
<api/auth/session>`.

.. _api/auth/session:

``/_session``
-------------

.. http:post:: /_session
  :synopsis: Authenticates user by Cookie-based user login

  Initiates new session for specified user credentials by providing `Cookie`
  value.

  :<header Content-Type: - :mimetype:`application/x-www-form-urlencoded`
                         - :mimetype:`application/json`
  :query string next: Enforces redirect after successful login to the specified
    location. This location is relative from server root. *Optional*.
  :form name: User name
  :form password: Password
  :>header Set-Cookie: Authorization token
  :>json boolean ok: Operation status
  :>json string name: Username
  :>json array roles: List of user roles
  :code 200: Successfully authenticated
  :code 302: Redirect after successful authentication
  :code 401: Username or password wasn't recognized

  **Request**:

  .. code-block:: http

    POST /_session HTTP/1.1
    Accept: application/json
    Content-Length: 24
    Content-Type: application/x-www-form-urlencoded
    Host: localhost:5984

    name=root&password=relax

  It's also possible to send data as JSON:

  .. code-block:: http

    POST /_session HTTP/1.1
    Accept: application/json
    Content-Length: 37
    Content-Type: application/json
    Host: localhost:5984

    {
        "name": "root",
        "password": "relax"
    }

  **Response**:

  .. code-block:: http

    HTTP/1.1 200 OK
    Cache-Control: must-revalidate
    Content-Length: 43
    Content-Type: application/json
    Date: Mon, 03 Dec 2012 01:23:14 GMT
    Server: CouchDB (Erlang/OTP)
    Set-Cookie: AuthSession=cm9vdDo1MEJCRkYwMjq0LO0ylOIwShrgt8y-UkhI-c6BGw; Version=1; Path=/; HttpOnly

    {"ok":true,"name":"root","roles":["_admin"]}

  If ``next`` query parameter was provided the response will trigger redirection
  to the specified location in case of successful authentication:

  **Request**:

  .. code-block:: http

    POST /_session?next=/blog/_design/sofa/_rewrite/recent-posts HTTP/1.1
    Accept: application/json
    Content-Type: application/x-www-form-urlencoded
    Host: localhost:5984

    name=root&password=relax

  **Response**:

  .. code-block:: http

    HTTP/1.1 302 Moved Temporarily
    Cache-Control: must-revalidate
    Content-Length: 43
    Content-Type: application/json
    Date: Mon, 03 Dec 2012 01:32:46 GMT
    Location: http://localhost:5984/blog/_design/sofa/_rewrite/recent-posts
    Server: CouchDB (Erlang/OTP)
    Set-Cookie: AuthSession=cm9vdDo1MEJDMDEzRTp7Vu5GKCkTxTVxwXbpXsBARQWnhQ; Version=1; Path=/; HttpOnly

    {"ok":true,"name":null,"roles":["_admin"]}


.. http:get:: /_session
  :synopsis: Returns Cookie-based login user information

  Returns complete information about authenticated user.
  This information contains :ref:`userctx_object`, authentication method and
  available ones and authentication database.

  :query boolean basic: Accept `Basic Auth` by requesting this resource.
    *Optional*.
  :code 200: Successfully authenticated.
  :code 401: Username or password wasn't recognized.

  **Request**:

  .. code-block:: http

    GET /_session HTTP/1.1
    Host: localhost:5984
    Accept: application/json
    Cookie: AuthSession=cm9vdDo1MEJDMDQxRDpqb-Ta9QfP9hpdPjHLxNTKg_Hf9w

  **Response**:

  .. code-block:: http

    HTTP/1.1 200 OK
    Cache-Control: must-revalidate
    Content-Length: 175
    Content-Type: application/json
    Date: Fri, 09 Aug 2013 20:27:45 GMT
    Server: CouchDB (Erlang/OTP)
    Set-Cookie: AuthSession=cm9vdDo1MjA1NTBDMTqmX2qKt1KDR--GUC80DQ6-Ew_XIw; Version=1; Path=/; HttpOnly

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


.. http:delete:: /_session
  :synopsis: Logout Cookie-based user

  Closes user's session.

  :code 200: Successfully close session.
  :code 401: User wasn't authenticated.

  **Request**:

  .. code-block:: http

    DELETE /_session HTTP/1.1
    Accept: application/json
    Cookie: AuthSession=cm9vdDo1MjA1NEVGMDo1QXNQkqC_0Qmgrk8Fw61_AzDeXw
    Host: localhost:5984

  **Response**:

  .. code-block:: http

    HTTP/1.1 200 OK
    Cache-Control: must-revalidate
    Content-Length: 12
    Content-Type: application/json
    Date: Fri, 09 Aug 2013 20:30:12 GMT
    Server: CouchDB (Erlang/OTP)
    Set-Cookie: AuthSession=; Version=1; Path=/; HttpOnly

    {
        "ok": true
    }


.. _api/auth/proxy:

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 :config:option:`httpd/authentication_handlers`:

   .. code-block:: ini

      [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 :ref:`userctx_object` for
remotely authenticated user. By default, the client just need to pass specific
headers to CouchDB with related request:

- :config:option:`X-Auth-CouchDB-UserName <couch_httpd_auth/x_auth_username>`:
  username;
- :config:option:`X-Auth-CouchDB-Roles <couch_httpd_auth/x_auth_roles>`:
  list of user roles separated by a comma (``,``);
- :config:option:`X-Auth-CouchDB-Token <couch_httpd_auth/x_auth_token>`:
  authentication token. Optional, but strongly recommended to
  :config:option:`force token be required <couch_httpd_auth/proxy_use_secret>`
  to prevent requests from untrusted sources.

**Request**:

.. code-block:: http

    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**:

.. code-block:: http

    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 :ref:`session <api/auth/session>`
to be authenticated by this method if all required HTTP headers are provided.


.. _api/auth/oauth:

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, :ref:`configure oauth <config/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:

.. code-block:: 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:

.. code-block:: 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:

.. code-block:: http

    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"

.. code-block:: http

    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 :ref:`_session <api/auth/session>` resource to ensure
that authentication was successful and the target CouchDB username is correct.
Change the target URL to request required resource.
