RESTful Authentication
Asked Answered
U

14

795

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.

Unrounded answered 26/11, 2008 at 1:47 Comment(5)
When I google Restful Authentication I find a dozen RoR plugins. I'm assuming those are NOT what you're looking for. If not RoR, then what language? What web server?Radiotelegraph
It won't be horribly wrong if you use HTTPS. The complete HTTP request along with the URL would be encrypted.Kuban
@BharatKhatri: Yes it would. I would never pass sensitive information in the URL visible to the user. This information is much more likely to leak for practical purposes. HTTPS can't help for accidental leakage.Haplosis
@jcoffland: What do you mean by real RESTful authentication? I am interested becouse I have just implemented the third way from the accepted answer, however I'm not happy with it (I dont like the additional param in the URL).Curly
some people use jwt.io/introduction to solve this.. I do research about this right now to solve my case : #36974663 >>Hopefully this will work fine.Pris
H
631

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.

Hawsepiece answered 23/8, 2011 at 9:29 Comment(17)
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.Turgeon
@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.Hawsepiece
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.Turgeon
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.Turgeon
I guess the correct answer is #6068613Bandicoot
@Bandicoot 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.Hawsepiece
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.Barton
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?Fleshpots
@Fleshpots 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.Hawsepiece
how about digest instead of basic?Precision
@Precision 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.Hawsepiece
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.Liqueur
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.Gaelic
@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.Hawsepiece
@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.Hawsepiece
@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 encodingMccleary
@ArnaudBouchez can you please help me on my post #60112243 ? ThanksDovelike
T
428

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?

Typhoeus answered 16/7, 2009 at 7:39 Comment(16)
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.Aut
@Aut 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.Typhoeus
@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. :)Aut
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.Hawsepiece
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.Typhoeus
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.Turgeon
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.Handspike
@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.Typhoeus
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.Cardie
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?Renfrew
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.Lanthanum
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 :)Sentimentalism
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".Liqueur
Hmm, nice insight. Any resources about this? Or did you discover it by reading the sources of amazon.com?Typhoeus
@Typhoeus I think he's referring to thisMagner
@Typhoeus Can you please check my question here and see if you can help ? #60112243Dovelike
M
156

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.

Marquismarquisate answered 26/11, 2008 at 1:47 Comment(7)
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)Whitson
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.Russel
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.Fleshpots
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.Marquismarquisate
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.Marquismarquisate
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.Fleshpots
@Fleshpots 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?Lingonberry
F
55

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.

Fleshpots answered 14/10, 2013 at 21:29 Comment(17)
What if someone gets hold of that auth token and invoke APIs with it pretending to be client?Loach
@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.Fleshpots
Why use public/private keys if both encryption and decryption takes place on the server?Brittney
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.Fleshpots
Is this any different to HMAC?Thermotensile
@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.Fleshpots
QPreexo, I suppose you could use the HMAC scheme but the idea is not limited to this.Fleshpots
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.Jervis
@Fleshpots 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).Jervis
...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.Jervis
@Loach You can add an expiration time to the token and/or bind it to the ip address.Wotton
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...Fervid
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 destrFervid
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.Doublure
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.Pathogenic
@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.Fleshpots
@Fleshpots This is an old post but in your solution, how does a resource server know which user the token is associated with? as well as what resources it has access to? I guess a workaround is to include a user identifier in the token but that removes the stateless-ness of this solution as there is now a need to keep track of issued tokens and the users they belong to. Which adds the need for resource servers to do a look up in some data store to check the token to user mapping to verify if the user is indeed allowed access to the resource it's requestingNavicert
J
42

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.

Joscelin answered 13/8, 2013 at 20:9 Comment(10)
People are not trying to forbid you from using sessions. You are free to do it. But if you do, it is not REST.Monegasque
@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).Joscelin
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?Tengler
"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.Joscelin
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.Liqueur
@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.Fleshpots
@Fleshpots 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.Joscelin
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.Hawsepiece
@ArnaudBouchez This is an old thread but can you expand on "orchestration services" to manage stateless services? does that mean that an orchestration service is the one responsible for state management in behalf of the stateless services? how would that work in practice? a stateless service pings the stateful service to verify requests before processing?Navicert
@Navicert The orchestrator is responsible to maintain its state in sync with the client. A typical way is by using a session. It will make the queries to the other services to retrieve the data, and keep a copy in its per-session memory/db. If the services store their own data, then they should be notified if it changed. Another way is to use events to communicate with the services, but the orchestrator only publish a stateful representation of the data, so it does not need to "ping" the services, but use the publish/subscribe pattern over them for each connected client.Hawsepiece
C
35

First and foremost, a RESTful web service is STATELESS (or in other words, SESSIONLESS). Therefore, a RESTful service does not have and should not have a concept of session or cookies involved. The way to do authentication or authorization in the RESTful service is by using the HTTP Authorization header as defined in the RFC 2616 HTTP specifications. Every single request should contain the HTTP Authorization header, and the request should be sent over an HTTPs (SSL) connection. This is the correct way to do authentication and to verify the authorization of requests in a HTTP RESTful web services. I have implemented a RESTful web service for the Cisco PRIME Performance Manager application at Cisco Systems. And as part of that web service, I have implemented authentication/authorization as well.

Cerebro answered 26/3, 2013 at 23:13 Comment(11)
HTTP authentication still requires the server to keep track of user ids and passwords. This is not completely stateless.Fleshpots
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.Edlyn
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.Fleshpots
@Fleshpots 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?Findley
@Fleshpots 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.Findley
@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.Fleshpots
SSL is not stateless.Mystique
@EddieB You're absolutely right, SSL is anything but stateless.Jervis
@Fleshpots 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.Jervis
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).Jervis
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 applicationFigure
S
24

It's certainly not about "session keys" as it is generally used to refer to sessionless authentication which is performed within all of the constraints of REST. Each request is self-describing, carrying enough information to authorize the request on its own without any server-side application state.

The easiest way to approach this is by starting with HTTP's built-in authentication mechanisms in RFC 2617.

Suspend answered 26/11, 2008 at 3:6 Comment(4)
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.Fleshpots
@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.Javierjavler
@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.Fleshpots
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.Lantern
I
17

Update on 16-Feb-2019

The approach mentioned earlier below is essentially "Resource Owner Password Credential" grant type of OAuth2.0. This is an easy way to get up and running. However, with this approach every application in the organization will end up with its own authentication and authorization mechanisms. The recommended approach is "Authorization Code" grant type. Additionally, in my earlier answer below I recommended browser localStorage for storing auth tokens. However, I've come to believe that cookie is the right option for this purpose. I have detailed my reasons, authorization code grant type implementation approach, security considerations etc. in this StackOverflow answer.


I think the following approach can be used for REST service authentication:

  1. Create a login RESTful API to accept username and password for authentication. Use HTTP POST method to prevent caching and SSL for security during transit On successful authentication, the API returns two JWTs - one access token (shorter validity, say 30 minutes) and one refresh token (longer validity, say 24 hours)
  2. The client (a web based UI) stores the JWTs in local storage and in every subsequent API call passes the access token in "Authorization: Bearer #access token" header
  3. The API checks the validity of the token by verifying the signature and expiry date. If the token is valid, check if the user (It interprets the "sub" claim in JWT as username) has access to the API with a cache lookup. If the user is authorized to access the API, execute the business logic
  4. If the token is expired, the API returns HTTP response code 400
  5. The client, on receiving 400/401, invokes another REST API with the refresh token in "Authorization: Bearer #refresh token" header to get a new access token.
  6. On receiving the call with refresh token, check if the refresh token is valid by checking the signature and the expiry date. If the refresh token is valid, refresh the access right cache of the user from DB and return new access token and refresh token. If the refresh token is invalid, return HTTP response code 400
  7. If a new access token and refresh token are returned, go to step 2. If HTTP response code 400 is returned, the client assumes that the refresh token has expired and asks for username and password from the user
  8. For logout, purge the local storage

With this approach we are doing the expensive operation of loading the cache with user specific access right details every 30 minutes. So if an access is revoked or new access is granted, it takes 30 minutes to reflect or a logout followed by a login.

Incoming answered 14/1, 2017 at 13:30 Comment(1)
so would you use this for an api with a static website made with angular for example? and what about mobile apps?Kei
W
15

The 'very insightful' article mentioned by @skrebel ( http://www.berenddeboer.net/rest/authentication.html ) discusses a convoluted but really broken method of authentication.

You may try to visit the page (which is supposed to be viewable only to authenticated user) http://www.berenddeboer.net/rest/site/authenticated.html without any login credentials.

(Sorry I can't comment on the answer.)

I would say REST and authentication simply do not mix. REST means stateless but 'authenticated' is a state. You cannot have them both at the same layer. If you are a RESTful advocate and frown upon states, then you have to go with HTTPS (i.e. leave the security issue to another layer).

Wrongheaded answered 15/10, 2012 at 19:35 Comment(5)
Stripe.com would say otherwise to your comment on REST and Authentication not mixing..Junette
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.Liqueur
Finally someone talking some sense, but stateless authentication is possible using public-key crypto. See my answer.Fleshpots
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.Findley
"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?Jervis
D
12

I think restful authentication involves the passing of an authentication token as a parameter in the request. Examples are the use of apikeys by api's. I don't believe the use of cookies or http auth qualifies.

Disembody answered 19/1, 2009 at 6:45 Comment(2)
Cookies and HTTP Auth should be avoided because of CSRF vulnerability.Liqueur
@DobesVandermeer Can you please see my question if you can help ? #60112243Dovelike
V
8

That's the way to do that: Using OAuth 2.0 for Login.

You may use other authentication methods other then Google's as long as it supports OAuth.

Velour answered 8/12, 2011 at 22:44 Comment(8)
OAuth2 is not secure without HTTPS, nor stateless.Hawsepiece
Nothing is secure without HTTPS.Jervis
@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) ;)Hawsepiece
@ArnaudBouchez Please clarify how having a broken certificate chain is for the greater good? I don't understand where you're going with that. ;)Jervis
@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.Hawsepiece
@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.Hawsepiece
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.Jervis
@Craig on mobile app a VPN proxy can send HTTPS for a toss unless SSL pinning is done.Solingen
I
4

Using a Public key infrastruction in which the registration of a key involves proper binding ensures that the public key is bound to the individual to which it is assigned in a way that ensures non-repudiation

See http://en.wikipedia.org/wiki/Public_key_infrastructure . If you follow the proper PKI standards, the person or agent who improperly uses the stolen key can be identified and locked out. If the agent is required to use a certificate, the binding gets pretty tight. A clever and quick-moving thief can escape, but they leave more crumbs.

Irita answered 2/11, 2013 at 4:8 Comment(0)
S
4

Tips valid for securing any web application

If you want to secure your application, then you should definitely start by using HTTPS instead of HTTP, this ensures a creating secure channel between you & the users that will prevent sniffing the data sent back & forth to the users & will help keep the data exchanged confidential.

You can use JWTs (JSON Web Tokens) to secure RESTful APIs, this has many benefits when compared to the server-side sessions, the benefits are mainly:

1- More scalable, as your API servers will not have to maintain sessions for each user (which can be a big burden when you have many sessions)

2- JWTs are self contained & have the claims which define the user role for example & what he can access & issued at date & expiry date (after which JWT won't be valid)

3- Easier to handle across load-balancers & if you have multiple API servers as you won't have to share session data nor configure server to route the session to same server, whenever a request with a JWT hit any server it can be authenticated & authorized

4- Less pressure on your DB as well as you won't have to constantly store & retrieve session id & data for each request

5- The JWTs can't be tampered with if you use a strong key to sign the JWT, so you can trust the claims in the JWT that is sent with the request without having to check the user session & whether he is authorized or not, you can just check the JWT & then you are all set to know who & what this user can do.

Many libraries provide easy ways to create & validate JWTs in most programming languages, for example: in node.js one of the most popular is jsonwebtoken

Since REST APIs generally aims to keep the server stateless, so JWTs are more compatible with that concept as each request is sent with Authorization token that is self contained (JWT) without the server having to keep track of user session compared to sessions which make the server stateful so that it remembers the user & his role, however, sessions are also widely used & have their pros, which you can search for if you want.

One important thing to note is that you have to securely deliver the JWT to the client using HTTPS & save it in a secure place (for example in local storage).

You can learn more about JWTs from this link

Shorten answered 15/10, 2018 at 18:16 Comment(0)
S
2

To answer this question from my understanding...

An authentication system that uses REST so that you do not need to actually track or manage the users in your system. This is done by using the HTTP methods POST, GET, PUT, DELETE. We take these 4 methods and think of them in terms of database interaction as CREATE, READ, UPDATE, DELETE (but on the web we use POST and GET because that is what anchor tags support currently). So treating POST and GET as our CREATE/READ/UPDATE/DELETE (CRUD) then we can design routes in our web application that will be able to deduce what action of CRUD we are achieving.

For example, in a Ruby on Rails application we can build our web app such that if a user who is logged in visits http://store.com/account/logout then the GET of that page can viewed as the user attempting to logout. In our rails controller we would build an action in that logs the user out and sends them back to the home page.

A GET on the login page would yield a form. a POST on the login page would be viewed as a login attempt and take the POST data and use it to login.

To me, it is a practice of using HTTP methods mapped to their database meaning and then building an authentication system with that in mind you do not need to pass around any session id's or track sessions.

I'm still learning -- if you find anything I have said to be wrong please correct me, and if you learn more post it back here. Thanks.

Saffren answered 19/1, 2009 at 6:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.