22

I'm building a PHP REST API that will be utilized from a JavaScript client, and am having some issues figuring out how to implement the auth and access side of things. There will be multiple applications that will use a JavaScript library that I'll be developing to talk and interact with my application. I'll be providing API keys to each of them, so that's not an issue.

Where I start getting confused is how to have the users on these sites authenticate to my application. It seems like a bad idea to have this external site store my user's account and password information; so, I guess I should have my JavaScript library include a login widget that asks for the user's account info for my application.

If authentication is successful there, since I'm working with a REST API, I'll need to store the token retrieved in a client side cookie or something so that the user doesn't need to login to my application again on every page of the external site. However, what happens if the user logs out of the external site, and then another user logs in from the same browser? As far as my JavaScript library is concerned, the old user would still be logged into my application, because the cookie/token would not have expired yet - how can I clear my cookie when the previous user's session ends? Or, am I completely off the right path here?

So, I'm thinking the process would be something like:

var token; // Some hashed string containing an expiration date and user id
var apiKey = '123abc';

// Read the cookie and check if it already contains the token
token = readCookie('token');
if (token == '') {
    // get username and password from user through some prompt

    var request_data = {apiKey: apiKey, user: username, pass: password};
    $.post('https://service.com/api/user/login', request_data, function(data) {
        token = data;
        document.cookie = "token=" + token;
    });
}

...

var get_data = {apiKey: apiKey, token: token};
$.get('http://service.com/api/<object>', get_data, function(data) {
    // Do something with data
});

Sorry, there's several questions buried in here. I guess the main one is if I'm storing the token to a cookie, how do I ensure that it is cleared when the user logs off of the external application? Or, if I shouldn't be storing it to a cookie, how do I keep the client aware of the user's state?

lightstrike
  • 954
  • 2
  • 15
  • 31
  • I think you should provide some `login`/`logout` methods in your js API, which your clients (those sites using your library in applications) should call according to their native login/logout sequence. If they do not require authentication, i'm afraid you can't intercept the moment when one user takes the place after another in same browser (for example, in some internet cafe). – Stan Jan 10 '13 at 18:29

3 Answers3

41

I suggest you to read this very good blog post about securing a RESTful API.

(In case that link doesn't work—it has already gone dead once and has to be retrieved from archive.org—I found what it seems to be a PDF render of this page accessible here: https://www.ida.liu.se/~TDDD97/labs/hmacarticle.pdf.)

Note: my answer is off-topic because the solution provided in the blog post above is not secure from a Javascript client. In fact, it explain mostly how to secure a REST API on the server side.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Epoc
  • 7,208
  • 8
  • 62
  • 66
  • 6
    First thing I've read that didn't conclude with "so use OAuth"... and a bonus it's pretty straightforward to understand, especially if you know a small bit about basic cryptography constructs already. Great find. – Kaganar Feb 03 '14 at 16:10
  • 8
    If you use HMAC from a JS client, the client should have the secret key to sign the requests, which turns it public, which makes it useless. – Alex Martín Jiménez Mar 07 '14 at 16:30
  • Since that link has gone down several times by now, it might be worth revisiting this answer and integrating the important information from the link into the answer itself. You can do that either by quoting the important bits (using blockquote formatting) and/or by summarizing them (using your own words). Leave the link to provide context. I think this would be worth it, as this has proven a pretty popular answer over the years. – Cody Gray - on strike Aug 10 '17 at 14:16
8

"Where I start getting confused is how to have the users on these sites authenticate to my application. It seems like a bad idea to have this external site store my user's account and password information;" -

With REST APIs, the best way to handle this is to use your clients (web pages, mobile apps) whether controlled by your domain or external pass through the user credentials entered by the user (in the login page). You would have a login/logout API that takes care of authenticating.

When the login API authenticates, it returns a token (one way hash maybe of user preferences of whatever), that can be stored in an encrypted cookie on the client side. This way, your clients never handle the user credentials directly. The token is set to expire whenever you want.

For all subsequent REST API calls, your clients will submit this token along with the request to the API (which is different from the login/logout API). The API may perhaps check a local cache (on the REST Server) to see if this is a valid token. If found, honors the request. Otherwise, throws an error.

If the user logs out before token expiration, then the login/logout API will delete this token from the local cache, and your clients will need to delete the session/cookie.

This way your credentials never get passed around on the client side.

And of course data-in-motion security should be achieved as well by SSL and HTTP Digest.

Kingz
  • 5,086
  • 3
  • 36
  • 25
1

If it's a private API (you have a users table) going cross-domain from another hostname to your own hostname, I agree with the above, and suggest a simple (SSL) Login/Logout at which point you can give the user (or take away) a cookies from your domain.

If it's a public API (anyone can get an API key for e.g.) I'd suggest use the method in the blog post from the answer above.

For the JavaScript client, try https://github.com/jpillora/jquery.rest if anything is missing, submit feature request or contribute if you like :)

jpillora
  • 5,194
  • 2
  • 44
  • 56