# Adding a new backend

Add new backends is quite easy, usually adding just a `class` with a couple settings and methods overrides to retrieve user data from services API. Follow the details below.

## Common attributes

First, lets check the common attributes for all backend types.

`name = ''`
  Any backend needs a name, usually the popular name of the service is used, like `facebook`, `twitter`, etc. It must be unique, otherwise another backend can take precedence if it’s listed before in `AUTHENTICATION_BACKENDS` setting.
`ID_KEY = None`
  Defines the attribute in the service response that identifies the user as unique in the service, the value is later stored in the `uid` attribute in the `UserSocialAuth` instance.
`REQUIRES_EMAIL_VALIDATION = False`
  Flags the backend to enforce email validation during the pipeline (if the corresponding pipeline `social.pipeline.mail.mail_validation` was enabled).
`EXTRA_DATA = None`
  During the auth process some basic user data is returned by the provider or retrieved by `user_data()` method which usually is used to call some API on the provider to retrieve it. This data will be stored under `UserSocialAuth.extra_data` attribute, but to make it accessible under some common names on different providers, this attribute defines a list of tuples in the form `(name, alias)` where `name` is the key in the user data (which should be a `dict` instance) and `alias` is the name to store it on `extra_data`.

## OAuth

OAuth1 and OAuth2 provide share some common definitions based on the shared behavior during the auth process, like a successful API response from `AUTHORIZATION_URL` usually returns some basic user data like a user Id.

### Shared attributes

`name`
  This defines the backend name and identifies it during the auth process. The name is used in the URLs `/login/<backend name>` and `/complete/<backend name>`.
`ID_KEY = 'id'`
  Default key name where user identification field is defined, it’s used on auth process when some basic user data is returned. This Id is stored in `UserSocialAuth.uid` field, this together the `UserSocialAuth.provider` field is used to unique identify a user association.
`SCOPE_PARAMETER_NAME = 'scope'`
  Scope argument is used to tell the provider the API endpoints you want to call later, it’s a permissions request granted over the `access_token` later retrieved. Default value is `scope` since that’s usually the name used in the URL parameter, but can be overridden if needed.
`DEFAULT_SCOPE = None`
  Some providers give nothing about the user but some basic data in required like the user Id or an email address. Default scope attribute is used to specify a default value for `scope` argument to request those extra used bits.
`SCOPE_SEPARATOR = ' '`
  The `scope` argument is usually a list of permissions to request, the list is joined used a separator, usually just a blank space, but differ from provider to provider, override the default value with this attribute if it differs.

### OAuth2

OAuth2 backends are fairly simple to implement; just a few settings, a method override and it’s mostly ready to go.

The key points on this backends are:

`AUTHORIZATION_URL`
  This is the entry point for the authorization mechanism, users must be redirected to this URL, used on `auth_url` method which builds the redirect address with `AUTHORIZATION_URL` plus some arguments (`client_id`, `redirect_uri`, `response_type`, and `state`).
`ACCESS_TOKEN_URL`
  Must point to the API endpoint that provides an `access_token` needed to authenticate in users behalf on future API calls.
`REFRESH_TOKEN_URL`
  Some providers give the option to renew the `access_token` since they are usually limited in time, once that time runs out, the token is invalidated and cannot be used any more. This attribute should point to that API endpoint.
`RESPONSE_TYPE`
  The response type expected on the auth process, default value is `code` as dictated by OAuth2 definition. Override it if default value doesn’t fit the provider implementation.
`STATE_PARAMETER`
  OAuth2 defines that an `state` parameter can be passed in order to validate the process, it’s kind of a CSRF check to avoid man in the middle attacks. Some don’t recognise it or don’t return it which will make the auth process invalid. Set this attribute to `False` in that case.
`REDIRECT_STATE`
  For those providers that don’t recognise the `state` parameter, the app can add a `redirect_state` argument to the `redirect_uri` to mimic it. Set this value to `False` if the provider likes to verify the `redirect_uri` value and this parameter invalidates that check.

Example code:

    from social.backends.oauth import BaseOAuth2

    class GithubOAuth2(BaseOAuth2):
        """Github OAuth authentication backend"""
        name = 'github'
        AUTHORIZATION_URL = 'https://github.com/login/oauth/authorize'
        ACCESS_TOKEN_URL = 'https://github.com/login/oauth/access_token'
        SCOPE_SEPARATOR = ','
        EXTRA_DATA = [
            ('id', 'id'),
            ('expires', 'expires')
        ]

        def get_user_details(self, response):
            """Return user details from Github account"""
            return {'username': response.get('login'),
                    'email': response.get('email') or '',
                    'first_name': response.get('name')}

        def user_data(self, access_token, *args, **kwargs):
            """Loads user data from service"""
            url = 'https://api.github.com/user?' + urlencode({
                'access_token': access_token
            })
            try:
                return json.load(self.urlopen(url))
            except ValueError:
                return None

### OAuth1

OAuth1 process is a bit more trickier, Twitter Docs explains it quite well. Beside the `AUTHORIZATION_URL` and `ACCESS_TOKEN_URL` attributes, a third one is needed used when starting the process.

`REQUEST_TOKEN_URL = ''`
  During the auth process an unauthorized token is needed to start the process, later this token is exchanged for an `access_token`. This setting points to the API endpoint where that unauthorized token can be retrieved.

Example code:

    from xml.dom import minidom

    from social.backends.oauth import ConsumerBasedOAuth

    class TripItOAuth(ConsumerBasedOAuth):
        """TripIt OAuth authentication backend"""
        name = 'tripit'
        AUTHORIZATION_URL = 'https://www.tripit.com/oauth/authorize'
        REQUEST_TOKEN_URL = 'https://api.tripit.com/oauth/request_token'
        ACCESS_TOKEN_URL = 'https://api.tripit.com/oauth/access_token'
        EXTRA_DATA = [('screen_name', 'screen_name')]

        def get_user_details(self, response):
            """Return user details from TripIt account"""
            try:
                first_name, last_name = response['name'].split(' ', 1)
            except ValueError:
                first_name = response['name']
                last_name = ''
            return {'username': response['screen_name'],
                    'email': response['email'],
                    'fullname': response['name'],
                    'first_name': first_name,
                    'last_name': last_name}

        def user_data(self, access_token, *args, **kwargs):
            """Return user data provided"""
            url = 'https://api.tripit.com/v1/get/profile'
            request = self.oauth_request(access_token, url)
            content = self.fetch_response(request)
            try:
                dom = minidom.parseString(content)
            except ValueError:
                return None

            return {
                'id': dom.getElementsByTagName('Profile')[0].getAttribute('ref'),
                'name': dom.getElementsByTagName(
                    'public_display_name')[0].childNodes[0].data,
                'screen_name': dom.getElementsByTagName(
                    'screen_name')[0].childNodes[0].data,
                'email': dom.getElementsByTagName(
                    'is_primary')[0].parentNode.getElementsByTagName(
                    'address')[0].childNodes[0].data,
            }

## OpenId

OpenId is fair simpler that OAuth since it’s used for authentication rather than authorization (regardless it’s used for authorization too).

A single attribute is usually needed, the authentication URL endpoint.

`URL = ''`
  OpenId endpoint where to redirect the user.

Sometimes the URL is user dependant, like in myOpenId where the URL is `https://<user handler>.myopenid.com`. For those cases where the user must input it’s handle (or full URL). The backend must override the `openid_url()` method to retrieve it and return a full URL to where the user will be redirected.

Example code:

    from social.backends.open_id import OpenIdAuth
    from social.exceptions import AuthMissingParameter

    class LiveJournalOpenId(OpenIdAuth):
        """LiveJournal OpenID authentication backend"""
        name = 'livejournal'

        def get_user_details(self, response):
            """Generate username from identity url"""
            values = super(LiveJournalOpenId, self).get_user_details(response)
            values['username'] = values.get('username') or \
                                 urlparse.urlsplit(response.identity_url)\
                                            .netloc.split('.', 1)[0]
            return values

        def openid_url(self):
            """Returns LiveJournal authentication URL"""
            if not self.data.get('openid_lj_user'):
                raise AuthMissingParameter(self, 'openid_lj_user')
            return 'http://%s.livejournal.com' % self.data['openid_lj_user']

## Auth APIs

For others authentication types, a `BaseAuth` class is defined to help. Those custom auth methods must override the `auth_url()` and `auth_complete()` methods.

Example code:

    from google.appengine.api import users

    from social.backends.base import BaseAuth
    from social.exceptions import AuthException

    class GoogleAppEngineAuth(BaseAuth):
        """GoogleAppengine authentication backend"""
        name = 'google-appengine'

        def get_user_id(self, details, response):
            """Return current user id."""
            user = users.get_current_user()
            if user:
                return user.user_id()

        def get_user_details(self, response):
            """Return user basic information (id and email only)."""
            user = users.get_current_user()
            return {'username': user.user_id(),
                    'email': user.email(),
                    'fullname': '',
                    'first_name': '',
                    'last_name': ''}

        def auth_url(self):
            """Build and return complete URL."""
            return users.create_login_url(self.redirect_uri)

        def auth_complete(self, *args, **kwargs):
            """Completes login process, must return user instance."""
            if not users.get_current_user():
                raise AuthException('Authentication error')
            kwargs.update({'response': '', 'backend': self})
            return self.strategy.authenticate(*args, **kwargs)