RESTful Authentication

415,921

Solution 1

How to handle authentication in a RESTful Client-Server architecture is a matter of debate.

Commonly, it can be achieved, in the SOA over HTTP world via:

  • HTTP basic auth over HTTPS;
  • Cookies and session management;
  • Token in HTTP headers (e.g. OAuth 2.0 + JWT);
  • Query Authentication with additional signature parameters.

You'll have to adapt, or even better mix those techniques, to match your software architecture at best.

Each authentication scheme has its own PROs and CONs, depending on the purpose of your security policy and software architecture.

HTTP basic auth over HTTPS

This first solution, based on the standard HTTPS protocol, is used by most web services.

GET /spec.html HTTP/1.1
Host: www.example.org
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

It's easy to implement, available by default on all browsers, but has some known drawbacks, like the awful authentication window displayed on the Browser, which will persist (there is no LogOut-like feature here), some server-side additional CPU consumption, and the fact that the user-name and password are transmitted (over HTTPS) into the Server (it should be more secure to let the password stay only on the client side, during keyboard entry, and be stored as secure hash on the Server).

We may use Digest Authentication, but it requires also HTTPS, since it is vulnerable to MiM or Replay attacks, and is specific to HTTP.

Session via Cookies

To be honest, a session managed on the Server is not truly Stateless.

One possibility could be to maintain all data within the cookie content. And, by design, the cookie is handled on the Server side (Client, in fact, does even not try to interpret this cookie data: it just hands it back to the server on each successive request). But this cookie data is application state data, so the client should manage it, not the server, in a pure Stateless world.

GET /spec.html HTTP/1.1
Host: www.example.org
Cookie: theme=light; sessionToken=abc123

The cookie technique itself is HTTP-linked, so it's not truly RESTful, which should be protocol-independent, IMHO. It is vulnerable to MiM or Replay attacks.

Granted via Token (OAuth2)

An alternative is to put a token within the HTTP headers so that the request is authenticated. This is what OAuth 2.0 does, for instance. See the RFC 6749:

 GET /resource/1 HTTP/1.1
 Host: example.com
 Authorization: Bearer mF_9.B5f-4.1JqM

In short, this is very similar to a cookie and suffers to the same issues: not stateless, relying on HTTP transmission details, and subject to a lot of security weaknesses - including MiM and Replay - so is to be used only over HTTPS. Typically, a JWT is used as a token.

Query Authentication

Query Authentication consists in signing each RESTful request via some additional parameters on the URI. See this reference article.

It was defined as such in this article:

All REST queries must be authenticated by signing the query parameters sorted in lower-case, alphabetical order using the private credential as the signing token. Signing should occur before URL encoding the query string.

This technique is perhaps the more compatible with a Stateless architecture, and can also be implemented with a light session management (using in-memory sessions instead of DB persistence).

For instance, here is a generic URI sample from the link above:

GET /object?apiKey=Qwerty2010

should be transmitted as such:

GET /object?timestamp=1261496500&apiKey=Qwerty2010&signature=abcdef0123456789

The string being signed is /object?apikey=Qwerty2010&timestamp=1261496500 and the signature is the SHA256 hash of that string using the private component of the API key.

Server-side data caching can be always available. For instance, in our framework, we cache the responses at the SQL level, not at the URI level. So adding this extra parameter doesn't break the cache mechanism.

See this article for some details about RESTful authentication in our client-server ORM/SOA/MVC framework, based on JSON and REST. Since we allow communication not only over HTTP/1.1, but also named pipes or GDI messages (locally), we tried to implement a truly RESTful authentication pattern, and not rely on HTTP specificity (like header or cookies).

Later Note: adding a signature in the URI can be seen as bad practice (since for instance it will appear in the http server logs) so it has to be mitigated, e.g. by a proper TTL to avoid replays. But if your http logs are compromised, you will certainly have bigger security problems.

In practice, the upcoming MAC Tokens Authentication for OAuth 2.0 may be a huge improvement in respect to the "Granted by Token" current scheme. But this is still a work in progress and is tied to HTTP transmission.

Conclusion

It's worth concluding that REST is not only HTTP-based, even if, in practice, it's also mostly implemented over HTTP. REST can use other communication layers. So a RESTful authentication is not just a synonym of HTTP authentication, whatever Google answers. It should even not use the HTTP mechanism at all but shall be abstracted from the communication layer. And if you use HTTP communication, thanks to the Let's Encrypt initiative there is no reason not to use proper HTTPS, which is required in addition to any authentication scheme.

Solution 2

I doubt whether the people enthusiastically shouting "HTTP Authentication" ever tried making a browser-based application (instead of a machine-to-machine web service) with REST (no offense intended - I just don't think they ever faced the complications).

Problems I found with using HTTP Authentication on RESTful services that produce HTML pages to be viewed in a browser are:

  • user typically gets an ugly browser-made login box, which is very user-unfriendly. you cannot add password retrieval, help boxes, etcetera.
  • logging out or logging in under a different name is a problem - browsers will keep sending authentication information to the site until you close the window
  • timeouts are difficult

A very insightful article that tackles these point by point is here, but this results in a lot of browser-specific javascript hackery, workarounds for workarounds, et cetera. As such, it is also not forward-compatible so will require constant maintenance as new browsers are released. I do not consider that clean and clear design, plus I feel it is a lot of extra work and headache just so that I can enthusiastically show my REST-badge to my friends.

I believe cookies are the solution. But wait, cookies are evil, aren't they? No, they're not, the way cookies are often used is evil. A cookie itself is just a piece of client-side information, just like the HTTP authentication info that the browser would keep track of while you browse. And this piece of client-side information is sent to the server at every request, again just like the HTTP Authentication info would be. Conceptually, the only difference is that the content of this piece of client-side state can be determined by the server as part of its response.

By making sessions a RESTful resource with just the following rules:

  • A session maps a key to a user id (and possibly a last-action-timestamp for timeouts)
  • If a session exists, then that means that the key is valid.
  • Login means POSTing to /sessions, a new key is set as a cookie
  • Logout means DELETEing /sessions/{key} (with the overloaded POST, remember, we're a browser, and HTML 5 is a long way to go yet)
  • Authentication is done by sending the key as a cookie at every request and checking whether the session exists and is valid

The only difference to HTTP Authentication, now, is that the authentication key is generated by the server and sent to the client who keeps sending it back, instead of the client computing it from the entered credentials.

converter42 adds that when using https (which we should), it is important that the cookie will have its secure flag set so that authentication info is never sent over a non-secure connection. Great point, hadn't seen it myself.

I feel that this is a sufficient solution that works fine, but I must admit that I'm not enough of a security expert to identify potential holes in this scheme - all I know is that hundreds of non-RESTful web applications use essentially the same login protocol ($_SESSION in PHP, HttpSession in Java EE, etc.). The cookie header contents are simply used to address a server-side resource, just like an accept-language might be used to access translation resources, etcetera. I feel that it is the same, but maybe others don't? What do you think, guys?

Solution 3

Enough already is said on this topic by good folks here. But here is my 2 cents.

There are 2 modes of interaction:

  1. human-to-machine (HTM)
  2. machine-to-machine (MTM)

The machine is the common denominator, expressed as the REST APIs, and the actors/clients being either the humans or the machines.

Now, in a truly RESTful architecture, the concept of statelessness implies that all relevant application states (meaning the client side states) must be supplied with each and every request. By relevant, it is meant that whatever is required by the REST API to process the request and serve an appropriate response.

When we consider this in the context of human-to-machine applications, "browser-based" as Skrebbel points out above, this means that the (web) application running in the browser will need to send its state and relevant information with each request it makes to the back end REST APIs.

Consider this: You have a data/information platform exposed asset of REST APIs. Perhaps you have a self-service BI platform that handles all the data cubes. But you want your (human) customers to access this via (1) web app, (2) mobile app, and (3) some 3rd party application. In the end, even chain of MTMs leads up to HTM - right. So human users remain at the apex of information chain.

In the first 2 cases, you have a case for human-to-machine interaction, the information being actually consumed by a human user. In the last case, you have a machine program consuming the REST APIs.

The concept of authentication applies across the board. How will you design this so that your REST APIs are accessed in a uniform, secured manner? The way I see this, there are 2 ways:

Way-1:

  1. There is no login, to begin with. Every request performs the login
  2. The client sends its identifying parameters + the request specific parameters with each request
  3. The REST API takes them, turns around, pings the user store (whatever that is) and confirms the auth
  4. If the auth is established, services the request; otherwise, denies with appropriate HTTP status code
  5. Repeat the above for every request across all the REST APIs in your catalog

Way-2:

  1. The client begins with an auth request
  2. A login REST API will handle all such requests
  3. It takes in auth parameters (API key, uid/pwd or whatever you choose) and verifies auth against the user store (LDAP, AD, or MySQL DB etc.)
  4. If verified, creates an auth token and hands it back to the client/caller
  5. The caller then sends this auth token + request specific params with every subsequent request to other business REST APIs, until logged out or until the lease expires

Clearly, in Way-2, the REST APIs will need a way to recognize and trust the token as valid. The Login API performed the auth verification, and therefore that "valet key" needs to be trusted by other REST APIs in your catalog.

This, of course, means that the auth key/token will need to be stored and shared among the REST APIs. This shared, trusted token repository can be local/federated whatever, allowing REST APIs from other organizations to trust each other.

But I digress.

The point is, a "state" (about the client's authenticated status) needs to be maintained and shared so that all REST APIs can create a circle of trust. If we do not do this, which is the Way-1, we must accept that an act of authentication must be performed for any/all requests coming in.

Performing authentication is a resource-intensive process. Imagine executing SQL queries, for every incoming request, against your user store to check for uid/pwd match. Or, to encrypt and perform hash matches (the AWS style). And architecturally, every REST API will need to perform this, I suspect, using a common back-end login service. Because, if you don't, then you litter the auth code everywhere. A big mess.

So more the layers, more latency.

Now, take Way-1 and apply to HTM. Does your (human) user really care if you have to send uid/pwd/hash or whatever with every request? No, as long as you don't bother her by throwing the auth/login page every second. Good luck having customers if you do. So, what you will do is to store the login information somewhere on the client side, in the browser, right at the beginning, and send it with every request made. For the (human) user, she has already logged in, and a "session" is available. But in reality, she is authenticated on every request.

Same with Way-2. Your (human) user will never notice. So no harm was done.

What if we apply Way-1 to MTM? In this case, since its a machine, we can bore the hell out of this guy by asking it submit authentication information with every request. Nobody cares! Performing Way-2 on MTM will not evoke any special reaction; its a damn machine. It could care less!

So really, the question is what suits your need. Statelessness has a price to pay. Pay the price and move on. If you want to be a purist, then pay the price for that too, and move on.

In the end, philosophies do not matter. What really matters is information discovery, presentation, and the consumption experience. If people love your APIs, you did your job.

Solution 4

Here is a truly and completely RESTful authentication solution:

  1. Create a public/private key pair on the authentication server.
  2. Distribute the public key to all servers.
  3. When a client authenticates:

    3.1. issue a token which contains the following:

    • Expiration time
    • users name (optional)
    • users IP (optional)
    • hash of a password (optional)

    3.2. Encrypt the token with the private key.

    3.3. Send the encrypted token back to the user.

  4. When the user accesses any API they must also pass in their auth token.

  5. Servers can verify that the token is valid by decrypting it using the auth server's public key.

This is stateless/RESTful authentication.

Note, that if a password hash were included the user would also send the unencrypted password along with the authentication token. The server could verify that the password matched the password that was used to create the authentication token by comparing hashes. A secure connection using something like HTTPS would be necessary. Javascript on the client side could handle getting the user's password and storing it client side, either in memory or in a cookie, possibly encrypted with the server's public key.

Solution 5

To be honest with you I've seen great answers here but something that bothers me a bit is when someone will take the whole Stateless concept to a extreme where it becomes dogmatic. It reminds me of those old Smalltalk fans that only wanted to embrace pure OO and if something is not an object, then you're doing it wrong. Give me a break.

The RESTful approach is supposed to make your life easier and reduce the overhead and cost of sessions, try to follow it as it is a wise thing to do, but the minute you follow a discipline (any discipline/guideline) to the extreme where it no longer provides the benefit it was intended for, then you're doing it wrong. Some of the best languages today have both, functional programming and object orientation.

If the easiest way for you to solve your problem is to store the authentication key in a cookie and send it on HTTP header, then do it, just don't abuse it. Remember that sessions are bad when they become heavy and big, if all your session consists of is a short string containing a key, then what's the big deal?

I am open to accept corrections in comments but I just don't see the point (so far) in making our lives miserable to simply avoid keeping a big dictionary of hashes in our server.

Share:
415,921
Jim Keener
Author by

Jim Keener

I am a software engineer. I enjoy hard problems and new languages. I railfan and am a model railroader.

Updated on July 10, 2022

Comments

  • Jim Keener
    Jim Keener almost 2 years

    What does RESTful Authentication mean and how does it work? I can't find a good overview on Google. My only understanding is that you pass the session key (remeberal) in the URL, but this could be horribly wrong.

  • johndodo
    johndodo almost 13 years
    This is a pragmatic answer and the proposed solution works. However, using terms "RESTful" and "session" in the same sentence is just wrong (unless there is also "not" in between ;). In other words: any web service that uses sessions is NOT RESTful (by definition). Don't get me wrong - you can still use this solution (YMMV), but the term "RESTful" can't be used for it. I recommend the O'Reilly book on REST which is very readable and explains the subject in depth.
  • skrebbel
    skrebbel almost 13 years
    @johndodo That may well be, but how do you then propose to do authentication? Or at least admit that it's simply impossible make a web app (app, not service!) that is RESTful (according to your strict definition). But the religious nerd war you're invoking has no practical use.
  • johndodo
    johndodo almost 13 years
    @skrebbel: pure REST solution would send authentication data each time it requests a resource, which is less than perfect (HTTP Auth does this). Proposed solution works and is better for most use cases, but it is not RESTful. No need for war, I use this solution too. I just don't claim it is RESTful. :)
  • Arnaud Bouchez
    Arnaud Bouchez almost 13 years
    Sessions are just one way of RESTful authentication - there are several ways available. And as stated by johndodo, it is not purely RESTful: this is just the common way of implementing it over HTTP.
  • skrebbel
    skrebbel almost 13 years
    Oh come on, give an example then. What's that other way, that works well? I'd genuinely like to know. HTTP Auth surely isn't, you can't logout without closing the browser and you can't offer decent login UX without lots of browser-specific non-future-compatible JS. I don't care that much about "purely RESTful" vs "almost RESTful" and the whole associated religious debate, but if you say there are several ways, you should spell them out.
  • Mikko Rantalainen
    Mikko Rantalainen over 12 years
    A truly RESTful authentication with real world user agents (a.k.a. "browsers") consists of a cookie containing the value of HTTP Authentication. This way the server can provide the UI for entering login and password and the server can force the logout (by deleting the cookie). In addition, instead of responding 401 to require login when authentication is failed, the server must use temporary redirect to login screen and after successful login use temporary redirect back to previous location. Plus the server must embed logout action (POST form) to pretty much every page for logged in users.
  • Haralan Dobrev
    Haralan Dobrev over 11 years
    I don't understand why this answer is more voted than the one from @ArnaudBouchez. He describes a third way with Query Authentication, which as he says probably the closest to the 'stateless' principle.
  • skrebbel
    skrebbel over 11 years
    @HaralanDobrev - it's simply a much older answer, so it had more time to gather upvotes. That said, I'm not sure how the Query Authentication option would map well to web applications. Note, we're talking about browsers viewing pages here, not programmed REST clients talking to REST servers. I haven't worked it out entirely, but I'm not sure I'd like authentication tokens to sit in my browser history, either.
  • Joe Phillips
    Joe Phillips over 11 years
    I don't see anything wrong with using "restful" and "session" in the same sentence as long as it's clear that the session exists only on the client side. I'm not sure why such a big deal is made about this concept.
  • yoshiwaan
    yoshiwaan over 11 years
    I've spend days reading the various threads on RESTful auth on SO. I've come to a similar conclusion that it's impossible to be 100% 'RESTful' to the most stringent requirements and have a browser access a secure API (without openID anyway). You can have a web app proxy to the API on behalf of the user, but then you have to add more code, it's obfuscation for the sake of ideals that don't apply in this situation. Even in the query signing below there needs to be a shared secret. Better to have a session than store a secret in a cookie imo, how else do you store the data client side?
  • Mikko Rantalainen
    Mikko Rantalainen about 11 years
    If you use Cookie as a better replacement for HTTP Basic Auth you can do truly stateless authentication with a method for expiring the authentication and ability to logout. An example implementation could use cookie called Emulated-HTTP-Basic-Auth with similar value to real HTTP Basic Auth and in addition set expire time. Log out can then be implemented with removing that cookie. I'd guess that any client able to support HTTP Basic Auth can also support cookie authentication done this way.
  • Arnaud Bouchez
    Arnaud Bouchez about 11 years
    @MikkoRantalainen But this cookie will still be managed by the server, as I wrote. It is some kind of stateless, but not "pure" stateless. In all cases, you need JavaScript code dedicated to client login/logout, which is perfectly possible e.g. with HTTP Digest Auth - good idea, but no big benefit, here, to reinvent the wheel.
  • Mikko Rantalainen
    Mikko Rantalainen about 11 years
    I would claim that server implements the UI and logic for configuring the header but the header itself is stateless. A client designed for the API could skip using server help for configuring the header and just pass the required information similar to HTTP Basic Auth. My point is that common UAs (browsers) have such a poor implementation of Basic Auth that it cannot be used. A server provided emulation for the same stuff in another header (Cookie) can be used instead.
  • Mikko Rantalainen
    Mikko Rantalainen about 11 years
    Of course, the server could support accepting both HTTP Basic Auth and Cookie. However, try to never request HTTP Basic Auth from a browser to avoid the bad UI.
  • graffic
    graffic about 11 years
    I guess the correct answer is stackoverflow.com/questions/6068113/…
  • Arnaud Bouchez
    Arnaud Bouchez almost 11 years
    @graffic In fact, this is what my answer proposed: even if sessions may be not 100% statefull, they are very handy and could/should be used with not fear. My point was that RESTful process should not be tied to HTTP specific patterns, like cookies or HTTP authentication. In our mormot.net framework, we implemented a light but powerful session management over REST authentication, without being bound to HTTP. See the last paragraph of my answer.
  • Abidi
    Abidi over 10 years
    What if someone gets hold of that auth token and invoke APIs with it pretending to be client?
  • Facundo Olano
    Facundo Olano over 10 years
    HTTP Basic auth can also be done via javascript right? so you don't necessarily need to stick to the ugly browser box. I'm thinking of a Single-Page App which may be unffair considering this answer is from '09, but you could do basic auth storing the credentials on the client and sending them in the header for every subsequent request you do via javascript.
  • André Caldas
    André Caldas over 10 years
    People are not trying to forbid you from using sessions. You are free to do it. But if you do, it is not REST.
  • arg20
    arg20 over 10 years
    @AndréCaldas it is not REST in the same way that having functions or primitive types in a language is not oop. I'm not saying having sessions is advisable. I'm just giving my opinion regarding following a set of practices to an extent they no longer provide someone with benefits. (Btw, notice I didn't oppose your remarks, however, I wouldn't say it's not REST, I'd say it's not pure REST).
  • mfhholmes
    mfhholmes over 10 years
    So what do we call it if it's not RESTful? And surely if a request includes the session Id, then that's as stateless as a request including a user Id? Why are user Id's stateless and session Id's stateful?
  • moliveira
    moliveira over 10 years
    If using cookies wouldn't that mean your client must have cookies enabled? If so, would it be more reliable for the server to define required auth headers instead? I have had good results doing so myself. The REST service of course would not dictate how the client stores the header values it needs to provide as credentials - the client could even use a cookie :)
  • vasilakisfil
    vasilakisfil over 10 years
    On the Query Authentication: (From the link you gave, credits @ Ron Wail ) "I don't agree with authentication information in the URL because it's the wrong place for it. URLs name resources, the HTTP headers are where things like authentication, content negotiation etc are supposed to be. Just because people have misunderstood REST as a style and insist on imposing RPC-like approaches via the URL doesn't mean that we should accomodate it." + you lose caching and proxying. I couldn't agree more with this guy.
  • jcoffland
    jcoffland over 10 years
    @Abidi, yes that's a problem. You could require a password. A hash of the password could be included in the authentication token. If someone was able to steal the token it would be vulnerable to offline brute force attacks. If a strong passphrase were chosen that would not be a problem. Note, that if you used https token theft would require the attacker to first gain access to the client's machine.
  • jcoffland
    jcoffland over 10 years
    None of these solutions is truly RESTful. Every single one requires some client specific state be kept on the server. Why is there such widespread misunderstanding of REST?
  • jcoffland
    jcoffland over 10 years
    HTTP authentication still requires the server to keep track of user ids and passwords. This is not completely stateless.
  • Arnaud Bouchez
    Arnaud Bouchez over 10 years
    @jcoffland You are right: "pure" RESTful is not authentication-friendly, by design. AFAIR a cookie can be implemented without any server-side state, just like Query Authentication. But it will probably make it less secure and convenient than some "light" server-side session. Perfectly statelessness (a RESTful-ism ?) is not a solution for all use cases IMHO.
  • Erik Martino
    Erik Martino over 10 years
    It is stateless in the sense that each request is valid on its own without any requirements of previous requests. How this is implemented on the server is another matter, if authentication is expensive you could do some caching and re-authenticate on cache miss. Very few servers are completely stateless where the output is purely a function of the input. It is usually a query of or an update to some state.
  • Gill Bates
    Gill Bates about 10 years
    Why use public/private keys if both encryption and decryption takes place on the server?
  • jcoffland
    jcoffland about 10 years
    Because only the authentication server knows the private key. Other servers can authenticate the user with only knowing the public key and the user's token.
  • Erik
    Erik about 10 years
    Stripe.com would say otherwise to your comment on REST and Authentication not mixing..
  • Vishnoo Rath
    Vishnoo Rath about 10 years
    Sir, you have explained this so beautifully that I have a clear idea of the basic issue / question at hand. You are like the Buddha! Might I add that by using HTTPS at the transport layer, we can even prevent Man In the Middle attacks, so that no one hijacks my identifier key (if Way-1 is chosen)
  • arg20
    arg20 about 10 years
    "Why are user Id's stateless and session Id's stateful?" I am guessing because sessions are volatile data. A session does not represent a business entity in most cases whereas a User can be considered persistent, business related data.
  • njzk2
    njzk2 about 10 years
    how about digest instead of basic?
  • Arnaud Bouchez
    Arnaud Bouchez about 10 years
    @njzk2 It won't change the problem: weird dialog popup to input the user/password credentials, then unsafe request to the server (digest is sensitive to MIM and Replay attacks). It is just a little better than basic, since the password is hashed during the transmission. This is why basic is still used a lot here, since it is easier to implement, and all security is left at HTTPS level. A two-way challenge, and URI signature is much safer.
  • Preexo
    Preexo about 10 years
    Is this any different to HMAC?
  • jcoffland
    jcoffland about 10 years
    @infostacker, sure why not. The human user can enter a password to unlock the token stored as a cookie or in local storage on their browser.
  • jcoffland
    jcoffland about 10 years
    QPreexo, I suppose you could use the HMAC scheme but the idea is not limited to this.
  • Dobes Vandermeer
    Dobes Vandermeer about 10 years
    The ugly password prompt for HTTP authorization will only appear if the server requests it by sending back the 401 Unauthorized response. If you don't like it, just send a 403 Forbidden instead. The error page may include a method to login or a link to it. However, but biggest argument against cookies AND http authentication (regardless of whether the state is server side or client side) is that they are vulnerable to cross-site request forgery. For this reason, the best approach is a custom Authorization scheme, custom authorization header, or custom GET or POST parameter.
  • Dobes Vandermeer
    Dobes Vandermeer about 10 years
    Cookies are vulnerable to cross-site request forgery, so they make it easier to have security breaches. Better to use something not automatically sent by the browser like a custom header or a custom Authorization scheme.
  • Dobes Vandermeer
    Dobes Vandermeer about 10 years
    Stateless only refers to the server, not the client. The client can remember all the state of the session and send what is relevant with each request.
  • Dobes Vandermeer
    Dobes Vandermeer about 10 years
    Cookies and HTTP Auth should be avoided because of CSRF vulnerability.
  • Dobes Vandermeer
    Dobes Vandermeer about 10 years
    If you use cookies then you open up the possibility of cross site request forgery. I think Amazon has got authentication right here. Their scheme is complex but secure and "RESTful".
  • skrebbel
    skrebbel almost 10 years
    Hmm, nice insight. Any resources about this? Or did you discover it by reading the sources of amazon.com?
  • itsadok
    itsadok almost 10 years
    @skrebbel I think he's referring to this
  • Todd Baur
    Todd Baur almost 10 years
    Isn't it always a machine doing the authentication? The human doesn't give a crap about passwords, it is an unfortunate annoyance to users who correctly rationalize security. To me it is a developer's problem how they want to have the machine do its work.
  • jcoffland
    jcoffland almost 10 years
    I'm sorry but what you describe is still not 100% REST because you are storing user credentials on a server. Those credentials are server side state. See my answer for a 100% RESTful authentication solution.
  • jcoffland
    jcoffland almost 10 years
    Not true. In this case all your requests require state from a previous transaction, namely the user registration. I don't see why people keep trying to say that a user name and password stored on the server is not server side state. See my answer.
  • jcoffland
    jcoffland almost 10 years
    HTTP authentication requires the server to store the user name and password. This is server side state and therefore not strictly REST. See my answer.
  • jcoffland
    jcoffland almost 10 years
    @arg20, user Ids are stateful. That's the mistake many people here are making. They want to overlook user Id's as state because there aren't any really good solutions for this available but they still want to call their application RESTful. Sure it's a bit pedantic but the OPs question was about 100% RESTful authentication.
  • jcoffland
    jcoffland almost 10 years
    Finally someone talking some sense, but stateless authentication is possible using public-key crypto. See my answer.
  • arg20
    arg20 almost 10 years
    @jcoffland I would only agree to your statement if your id changes over time, which wouldn't make sense in most real case scenarios. If your id is unchangeable, I don't see how it needs to keep state.
  • Michael Ekoka
    Michael Ekoka almost 10 years
    @jcoffland Your solution works very well and is rather elegant, but may I suggest that you review your definition of "state" when it comes to REST? Everything I read about REST in that regard seems to refer to something in the request that provokes a significant change of state on the server. How does retrieving auth information accomplish this? Before you answer, consider the case where access not only needs to be authenticated, but then also authorized. How do you go around storing the username or something similar to your API server?
  • Michael Ekoka
    Michael Ekoka almost 10 years
    @jcoffland Also, your solution relies heavily on the ability of the API server to decrypt the signed token. I think that this approach is not only way too specific, but also a tad bit too sophisticated to be thought of as THE approah R. Fielding had in mind to tackle the problem of RESTful authentication.
  • Michael Ekoka
    Michael Ekoka almost 10 years
    The server has no "authenticated" state. It receives information via hypermedia and has to work with it to return what was requested. Nothing less, nothing more. If the resource is protected and requires authentication and authorization, the provided hypermedia must include that information. I don't know where the notion that authenticating a user before returning a resource means that the server is tracking state comes from. Providing a username and a password can very well be thought of as simply providing more filtering parameters.
  • Kingz
    Kingz almost 10 years
    I read your answer; in your solution, for every single web request originating on the browser by user clicks will need to send the "auth token" back to whatever API the user click is calling. What then? The API performs the check on the token. Against what? Against some kind of "token store" that maintains whether that token is valid or not. Do you not agree that that "token store" then becomes the keeper of "state"? Really, however way you see this, someone somewhere has to know something about the "tokens" being passed around on user activities. Thats where the state info lives.
  • Kingz
    Kingz almost 10 years
    And by "stateless" service, what is really meant is that that particular server component (the CRUD APIs) do not carry any states. They do not recognize one user from another and complete the user request in its entirety in one transaction. That is statelessness. But someone somewhere must be sitting and passing judgment on whether this user is valid or not. There is no other way to do this; keys or passwords or whatever. Anything passed around from the user side must be authenticated and authorized.
  • jcoffland
    jcoffland almost 10 years
    @mike I agree that this is not currently THE approach but if someone were to implement it then it could become THE approach. For example, Google could implement this as oauth 4.0 where Google issues login tokens in this form to users which your server could verify by checking Google's signature and the timestamp. Also, nearly all server side software has the capability to do this kind of crypto. It's built into Python, Java, PHP, node.js, etc.
  • Boris B.
    Boris B. almost 10 years
    @jcoffland: That is simply not true, on both accounts. First HTTP Auth doesn't require of the server to store the password. The hash of the password is stored instead (bcrypt with 8+ rounds recommended). Second, the server doesn't have any state since the authorization header is sent with every request. And if you consider stored password hashes as state, they are no more state than stored public keys are.
  • jcoffland
    jcoffland almost 10 years
    @Boris B., yes I understand that the password is stored as a hash. The hashed password is still client specific state. The difference with storing a public-key, as described in my solution, is that there is only one public-key, the public-key of the authentication server. This is very different than storing a password hash per user. No matter how you dress it up if the server stores a password for each user then it is storing per user state and is not 100% REST.
  • Incerteza
    Incerteza over 9 years
    I wonder, why do you assume that API requests are sent via a browser? Likely they are sent via curl or a client in some programming language.
  • Arnaud Bouchez
    Arnaud Bouchez over 9 years
    @AlexanderSupertramp I do not make this assumption, I just stated on the contrary that REST should not be tied to HTTP (like using cookies). This is the main point of this answer, in fact. With our in-house Open Source framework, you can create AJAX/Browser apps, Windows clients, and even stand-alone apps, all using REST patterns, and JSON - and in fact, this was a great design choice, e.g. for security or evolution. :) If run from a browser, a basic authentication would popup an awful dialog box to enter name and password.
  • Codepunkt
    Codepunkt over 9 years
    I don't think storing a users hashed password on the server should be considered server-side state. Users are resources, containing information like name, address or hashed password.
  • Edward J Beckett
    Edward J Beckett over 9 years
    SSL is not stateless.
  • Arnaud Bouchez
    Arnaud Bouchez about 9 years
    In fact, trying to be stateless is not about dogmatism, but about one common conception of SOA itself. Services should always benefit from being uncoupled, and stateless: in practice, it eases scaling, availability and maintainability. Of course, it should be as much as possible, and you would eventually need some "orchestration services" to manage those stateless services into a stateful pragmatic approach.
  • Arnaud Bouchez
    Arnaud Bouchez about 9 years
    OAuth2 is not secure without HTTPS, nor stateless.
  • Craig Tullis
    Craig Tullis about 9 years
    Asymmetrical encryption and decryption is an order of magnitude slower (more compute-intensive) than symmetrical encryption.Having the server using the public key to decrypt the token on every call would be an enormous performance bottleneck.
  • Craig Tullis
    Craig Tullis about 9 years
    @EddieB You're absolutely right, SSL is anything but stateless.
  • Craig Tullis
    Craig Tullis about 9 years
    @jcoffland do you understand how profoundly more compute-intensive (and therefore resource-intensive and profoundly slow) asymmetrical encryption is? You're talking about a scheme that would use asymmetrical encryption on every single request. The slowest aspect of HTTPS, bar nothing, is the initial handshake which involves creation of public/private keys to asymmetrically encrypt a shared secret that is subsequently used to symmetrically encrypt all ensuing communication.
  • Craig Tullis
    Craig Tullis about 9 years
    Symmetrical encryption is so fast that the overhead of using it is negligible, entirely unlike asymmetrical encryption. So, that shared secret is stored as (gasp) state on both the client and the server. And in fact the performance issues are so pronounced that HTTP keep-alives are used to keep connections open between clients and servers (more state), specifically in order to avoid the large computational capital you spend every time you invoke an asymmetrical encryption function (look up the SPDY protocol).
  • Craig Tullis
    Craig Tullis about 9 years
    "I would say REST and authentication simply do not mix." Sounds like some common sense. Except that a system that is incompatible with authentication ("authenticated" itself is, of course, a state) is of limited usefulness. I feel like we're all arguing at the intersection of practicality and purist dogmatism, and frankly practicality ought to win. There are plenty of aspects of REST that are highly beneficial without going into contortions trying avoid state with respect to authentication, aren't there?
  • Craig Tullis
    Craig Tullis about 9 years
    Nothing is secure without HTTPS.
  • Craig Tullis
    Craig Tullis about 9 years
    @jcoffland you really promoted your answer here (repeatedly :-) But I can't help commenting on the performance issues (compute intensity) of using asymmetrical encryption on every call. I just can't see a solution that does that having any ability to scale. Look up HTTPS and the SPDY protocol. It goes to lengths to keep connections open (HTTP keep-alives, which is state), and serve multiple resources in batches over the same connection (more state), and of course SSL itself only uses asymmetrical encryption to exchange a symmetrical cipher key (also state).
  • Craig Tullis
    Craig Tullis about 9 years
    ...because symmetrical encryption is an order of magnitude faster than asymmetrical encryption. The slowest, most pipe-clogging aspect of HTTPS is the initial handshake involving the use of public/private keys to encrypt messages. If HTTPS didn't switch to the shared secret symmetrical encryption for all ensuing communication, then actual, practical real-world performance would just be unacceptable and the solution could never scale, at least not without unacceptable resource costs.
  • inf3rno
    inf3rno over 8 years
    @Abidi You can add an expiration time to the token and/or bind it to the ip address.
  • jcoffland
    jcoffland over 8 years
    You are missing Way-3, the hybrid approach. The client logs in as in Way-2 but, as in Way-1, the credentials are not checked against any server side state. Regardless, an auth token is created and sent back to the client as in Way-2. This token is later checked for authenticity using asymmetric crypto with out looking up any client specific state.
  • Arnaud Bouchez
    Arnaud Bouchez over 8 years
    @Craig And HTTPS may not be secure either, if the certificates chain is broken, which may be for greater good - en.wikipedia.org/wiki/Bullrun_(decryption_program) ;)
  • Newbie
    Newbie over 8 years
    I'm doing now a token based "pseudo-REST" (to prevent people to say, that is not RESTFUL cause you store a token on the server)... btw while coding for a while, mixing RAM based and HD based db, to improve check spead of each token, while smoking a sigaret I came up with tha same crazy idea: "why not simply pack a credential confirm JSON and AES cript it, no one can reproduce id, i have no worry about DB look-ups, i can store whatever i want there"... well i have just a concern that is preventin me from switching from 4000 java line code to this that would be maybe 100 lines solution...
  • Newbie
    Newbie over 8 years
    I lose completely control over the tokens. What if someone logout? In theory the token is still valid, no one perform major tests than decrypt and check if exp date is still greater than now(). If user let say, decide that maybe someone stoled his credentials, and 'change password' what does it mean? I'm not looking back on any server while processing the token... it would work? YES, there would be people lookin to steal those tokens? Maybe, not easier than stealing a password, but password can change, i agree with the user for a new one, such token is like a passepartout that can not be destr
  • Craig Tullis
    Craig Tullis about 8 years
    @ArnaudBouchez Please clarify how having a broken certificate chain is for the greater good? I don't understand where you're going with that. ;)
  • Arnaud Bouchez
    Arnaud Bouchez almost 8 years
    @Craig Please follow the link, and enjoy! This "greater good" approach was clearly cynical in my comment: Bullrun-like systems are meant for "our own good" by our beloved and trustful governments.
  • Arnaud Bouchez
    Arnaud Bouchez almost 8 years
    @Craig My point was that even HTTPS is not fully secure, so OAuth 2 is a broken standard. If your HTTPS is compromised due to a broken certificate chain, since only the server is authenticated (there is usually no mutual authentication), you can inpersonate the server and perform a Man In The Middle attack. Then, the MIM server will intercept the OAuth2 token plain value, and use it to forge fake requests to the real server.
  • Craig Tullis
    Craig Tullis almost 8 years
    So, HTTPS, presuming an unbroken cert chain (your browser will warn you), and presuming a root cert hasn't been compromised, and presuming a site isn't redirecting from HTTP to HTTPS, thus enabling SSLstrip attacks (which the user will catch if they're diligent because SSLstrip will NOT fool the browser into thinking it has a secure connection), then HTTPS is fine, for now at least. One glaring problem is dumb app developers who intentionally bypass cert chain verification, because it's kind of hard to get it right. But that's on the app developers, not on HTTPS. It isn't that hard.
  • Merlyn Morgan-Graham
    Merlyn Morgan-Graham over 7 years
    @jcoffland what you describe is a system which determines that a user has passed an authentication check at some point, but not which authentication check. You don't know who they are, let alone what they have access to, just that they supplied passing credentials at some point. How do you find out who they are, and whether they should have access to the current resource? Or can all authenticated users on your system access all protected resources?
  • Greeso
    Greeso over 7 years
    In step 3, you say: "When a client authenticates". How do you do that? By sending user ID and password to the server? Or by sending the public key? Thanks.
  • amar
    amar about 7 years
    @Craig on mobile app a VPN proxy can send HTTPS for a toss unless SSL pinning is done.
  • doesnt_matter
    doesnt_matter about 7 years
    yes sure http aka rest is stateless, all auth is on top of it. so yes all of api solutions drift a bit from pure rest . and... we have to use auth on top of rest. the way the auth is implemented can be whatever suits the application
  • rintaun
    rintaun almost 7 years
    There are a lot of problems with this solution. Strictly speaking, it may be "truly RESTful" authentication. Many problems have been outlined in comments on this and other answers, but there seem to be two core flaws: 1) efficiency and 2) security. 1) It is very problematic at scale to perform asymmetric encryption to verify the issued token on every request. 2) Authentication becomes locked in time at the point of issuance; any subsequent change in user credentials or access has no effect. That is the worst (and most dangerous) part of this security scheme, and calls for extreme caution.
  • jcoffland
    jcoffland over 6 years
    @rintaun, not every application needs to scale to the point where this would matter. I would even go as far as saying, most applications do not require that level of scaling. Regarding security, it is completely possible to grant time-limited credentials and require users to renew expired tokens to gain access to resources. Token renewing can be automatic and hidden to the user. When new tokens are reissued permissions can be added or removed. But if you are tracking user permissions in a DB somewhere then it's not really RESTful anyway so your second point is moot.
  • Arnaud Bouchez
    Arnaud Bouchez over 5 years
    @Alvin I removed your stackoverflow.com/revisions/7158864/9 because editing an answer is not how to make a comment. I added a small note to my answer about potential concerns raised by signature in URI.
  • Alvin
    Alvin over 5 years
    @ArnaudBouchez I get it -- not the right way to fix this answer -- but I don't think your comment correctly notes the significance of this vulnerability -- this was a way to do things years ago but an entire http header was added to address it and SHOULD be used in place of this approach EVERY TIME POSSIBLE -- encrypted connections aren't worth much if your credentials aren't encrypted with them -- this being an accepted answer PLEASE update or add a stronger note about the recommended use of the Authorized header vs URI encoding
  • Hemant Metalia
    Hemant Metalia over 4 years
    @ArnaudBouchez can you please help me on my post stackoverflow.com/questions/60111743/… ? Thanks
  • Hemant Metalia
    Hemant Metalia over 4 years
    @skrebbel Can you please check my question here and see if you can help ? stackoverflow.com/questions/60111743/…
  • Hemant Metalia
    Hemant Metalia over 4 years
    @DobesVandermeer Can you please see my question if you can help ? stackoverflow.com/questions/60111743/…
  • Yazan Rawashdeh
    Yazan Rawashdeh about 4 years
    so would you use this for an api with a static website made with angular for example? and what about mobile apps?