Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Building an API-driven website with API authentication and users that aren't logged in

I've built a website that provides search results on legal documents. Among the features of the site is a REST API. Currently when somebody submits a query, the entire page is reloaded and the API is hit server side. I'd like to rebuild the site so that as people tweak search parameters, the results are paged in client-side using AJAX that hits the REST API.

The API requires a login (so that it can be throttled if needed), but using the site in general doesn't.

How can I make it so that people can use the site without logging in, but their use of the site hits the API client side?

The best ideas I currently have are:

  1. Just put a username and password into the site's JavaScript and use them to log into the API when making queries. Give these credentials unthrottled access to the API. This could work, aside from putting credentials into my JavaScript.

  2. Continue doing all API work server-side, foregoing the speed and UX improvements that come from dynamic page reloads.

Doing number 1 sucks and doing number 2 is basically giving up on having the kind of site I want.

Ideas?

like image 243
mlissner Avatar asked Feb 10 '23 12:02

mlissner


2 Answers

Perhaps this is a duplicated of "How to make sure that my AJAX requests are originating from the same server in Python"? I don't want to flag it in case I just don't understand the difference in what this poster is asking vs that poster.


According to your site's API info page, you're using tastypie, and BasicAuthentication is being used for your API users

Have you tried combining BasicAuthentication with another authentication option via MultiAuthentication? Perhaps you could use SessionAuthenticaion and using an authentication backend that allows anonymous. That way API users would continue to pass their username/password (API key if you go that route), and users of the site would fall back to an anonymous session, authenticated via SessionAuthenticaton.

Or instead of SessionAuthentication, create a custom authentication, as demonstrated here, and use some logic to determine if the consumer resides on the same host as the API.


Tastypie's ApiKeyAuthentication method can be configured to use a custom header...

enter image description here


Migrated and incorporated from comments:

Based on How does Google Maps secure their API Key? (I prefer Franci Penov's answer to the accepted one) If I were going to implement this I would use a two step process of ApiKeyAuthentication to confirm a valid API key, followed by a "referral check", to make sure the key is coming from the expected source. This is made simpler if the key is calculated based on the source, as suggested in the answer linked above.

There's actually code in tastypie's SessionAuthentication method (authentication.py) that does something similar...

...

referer = request.META.get('HTTP_REFERER')

if referer is None:
    return False

good_referer = 'https://%s/' % request.get_host()

if not same_origin(referer, good_referer):
    return False

...
like image 120
Eric Lease Avatar answered Feb 13 '23 02:02

Eric Lease


In addition to the answers already provided here, one suggestions of what you could do in this situation is that you can have a custom authorization headers. One example could be the way amazon does it.

Having a custom authorization header reqiures you to create the header yourself.

What you could do is have the client(the one that makes the call, not necessarily the user) authenticate once per session. Store that auth-token somewhere, and use it to sign each request to the rest-api. That auth-token would only be valid for a certain period of time, so no danger in someone missusing it.

Here is one other article I've found on authorization with custom headers in .NET

like image 23
TheBoyan Avatar answered Feb 13 '23 01:02

TheBoyan