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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@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.

1
Basic dXNlcm5hbWU6cGFzc3dvcmQ=

The header can be decoded with the base64 module.

1
2
3
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 .

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@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?

See also