Authentication

Lego uses CORS to deny requests from other domains than the once we control. OAuth2 authorization is required if you want to create an app that consumes information from the Lego API.

JSON Web Tokens

To authenticate using JWT, post to /api/token-auth/ with a username and password. This will return a token, which can later be used with the following header: Authorization: JWT <insert token here>.

To refresh a token, post to /api/token-auth/refresh with the token in the body. Both these endpoints can be used with JSON and regular forms.

The webapp uses this authentication flow, third party apps should use OAuth2.

OAuth2

Lego has support for OAuth2 authentication using the authorization-code method. Everyone with a valid user and the right permissions is able to create an OAuth2 application. This works in the same way as Login with GitHub or any other OAuth2 system.

You should never expose the client_secret to the public. Never implement the OAuth2 authorization flow in a browser.

The snippet below can be used together with python-social-auth to authenticate with Lego as the user directory.

We currently have two scopes.

  • user - This scope gives read access access to basic user information: Name, username, profile picture, email and the users memberships. This information can be found in /api/v1/users/oauth2_userdata/

  • all - This scope gives full read & write access to everything. Including password change.

from six.moves.urllib.parse import urljoin

from social_core.backends.oauth import BaseOAuth2


class LegoOAuth2(BaseOAuth2):

    name = 'lego'
    ACCESS_TOKEN_METHOD = 'POST'
    SCOPE_SEPARATOR = ','
    EXTRA_DATA = [
        ('id', 'id'),
        ('expires_in', 'expires_in'),
    ]

    def api_url(self):
        api_url = self.setting('API_URL')
        if not api_url:
            raise ValueError('Please set the LEGO_API_URL setting.')
        return api_url

    def get_scope(self):
        return ['user'] # Only use ['all'] when necessary (aka. never)

    def authorization_url(self):
        return urljoin(self.api_url(), '/authorization/oauth2/authorize/')

    def access_token_url(self):
        return urljoin(self.api_url(), '/authorization/oauth2/token/')

    def get_user_details(self, response):
        """Return user details from Lego account"""
        fullname, first_name, last_name = self.get_user_names(
            response.get('fullName'),
            response.get('firstName'),
            response.get('lastName')
        )
        return {'username': response.get('username'),
                'email': response.get('email') or '',
                'fullname': fullname,
                'first_name': first_name,
                'last_name': last_name}

    def user_data(self, access_token, *args, **kwargs):
        return self._user_data(access_token)

    def _user_data(self, access_token):
        url = urljoin(self.api_url(), 'api/v1/users/me/')
        return self.get_json(url, headers={'AUTHORIZATION': 'Bearer %s' % access_token})