Using Basic Authentication with Google Cloud Endpoints

Cloud Endpoints provides strong integration with OAuth 2.0. If you can use this integration – do it. However, some legacy systems require supporting alternative authentication mechanisms. This article will show you how to secure an API endpoint using Basic Authentication. You can use this as a starting point for whatever authentication method you choose.

A basic endpoint

As a starting point let’s define a basic endpoint that will return a hypothetical UserMessage defining a User resource.

@endpoints.api(name='users', version='v1', description='Users Api')
class UsersApi(remote.Service):

    @endpoints.method(message_types.VoidMessage,
                      UserMessage,
                      http_method='GET',
                      path='user',
                      name='user.auth')
    def user_auth(self, request):
        ## Return a UserMessage

Let’s build up a UserMessage based on the credentials set in the HTTP Authorization header. We can access the HTTP headers of the request through the HTTPRequestState using the instance variable request_state.

@endpoints.api(name='users', version='v1', description='Users Api')
class UsersApi(remote.Service):

    @endpoints.method(message_types.VoidMessage,
                      UserMessage,
                      http_method='GET',
                      path='user',
                      name='user.auth')
    def user_auth(self, request):
        basic_auth = self.request_state.headers.get('authorization')
        print basic_auth
        ## Return a UserMessage

We can test this endpoint using httpie.

http -a username:password GET :8888/_ah/api/users/v1/user

Examing the logs will show that we receive the HTTP Authorization header in its base64 encoded form.

Basic dXNlcm5hbWU6cGFzc3dvcmQ=

The header can be decoded with the base64 module.

basic_auth = self.request_state.headers.get('authorization')
auth_type, credentials = basic_auth.split(' ')
print base64.b64decode(credentials)  # prints username:password

Using the username and password we can check the datastore for a User model with the same credentials and return a UserMessage based on the model .

@endpoints.api(name='users', version='v1', description='Users Api')
class UsersApi(remote.Service):

    @endpoints.method(message_types.VoidMessage,
                      UserMessage,
                      http_method='GET',
                      path='user',
                      name='user.auth')
    def user_auth(self, request):
        basic_auth = self.request_state.headers.get('authorization')
        auth_type, credentials = basic_auth.split(' ')
        username, password = base64.b64decode(credentials).split(':')
        user = User.get_by_username(username)
        if user and user.verify_password(password):
            return user.to_message()
        else:
            raise endpoints.UnauthorizedException

This should serve as a starting point for anyone wishing to use Basic Authentication with Google Cloud Endpoints. If you’ve read this far, why not subscribe to this blog through email or RSS?

comments powered by Disqus