Asitaka
Asitaka

Reputation: 375

How can I require an api-token field on requests?

I'm currently building a Google Cloud Endpoints backend with the endpoints-proto-datastore library, and am running into trouble requiring an apikey when you request a user. Once a user logs in, they receive an APIkey which they send back for successive puts (which works) but how do I require the username/email and apikey on a GET ? Currently if a user does a get like so:

@User.method(request_fields=('id', 'apiToken',), path='users', http_method='GET', name='user.get')
def user_get(self, query):
    return query

The user is pulled from the datastore because the ID is correct, and it completely ignores the apiToken. How do I require both fields? (on a different note, how do I send back the user's ID on a request?)

Upvotes: 2

Views: 103

Answers (2)

Asitaka
Asitaka

Reputation: 375

The easiest way I found to do this is:

   @User.method(request_fields=('id', 'apiToken',), path='users', http_method='GET', name='user.get')
def user_get(self, user_model):
    user = ndb.Key('User', int(user_model.id)).get()
    if user.apiToken != user_model.apiToken:
        raise endpoints.UnauthorizedException('You are not authorized to view this data')
    return user.clean()

The user_model will have the userId and the apiToken stored in it, so I pull the "real" data from ndb with the key and check if the user_model has the correct token and return the model if it is correct, if not, I refuse

Upvotes: 1

Adam
Adam

Reputation: 6005

If you are implementing your own API key scheme, as your code suggests, then you need to manually check if the API key is valid or not yourself.

Your example looks like the one from the 'basic' example, and you've added parameters as per the 'simple_get' example. For some background, the docs in the 'simple_get' example mention that 'id' is one of five special helper properties automatically defined by EndpointsModel for common operations like retrieving by id. This is why your code works automatically without you doing anything 'special' with the 'id' parameter. The example still checks though that the entity exists if you try to get it:

if not my_model.from_datastore:
      raise endpoints.NotFoundException('MyModel not found.')

Since there's no special helper property for your 'apiKey' field, you need to add your own code in the method to check if the key is valid and return a 401 or suitable error if it's not. Another option is to also utilize some of Google's built-in authentication as per the 'basic_with_auth' example.

Finally, since endpoints-proto-datastore is just syntactic sugar for the main endpoints library, you'll want to read the full documentation on that for more information on things like how to return values from your endpoints methods.

Upvotes: 1

Related Questions