115

I heard that a "RESTful API should be stateless. All state info should be kept on client side".

But when I issue an AJAX call from a web page, I noticed that a session ID cookie is always sent along to the server. With that session ID, I can obtain the session object on the server, and thus I can "get/set some state info in the session".

Does this break the "code of being stateless" for a RESTful API?

ADD 1

(The background of my question is as below.)

I tried to implement a login page by calling a RESTful API to validate a username and a password.

Each time a user attempts to visit a page of my site, a login servlet filter will check the session (this is where getSession() gets called) for that user to see if valid login info exists. If not, the login filter will redirect the user to the login page.

On the login page, an AJAX call is made to a RESTful API on the server with the username and the password. Depending on the result of that RESTful API call, the JavaScript on the page will decide whether to let the user into my site.

So, in this scenario, I kind of have to use session.

The detailed code is located here: Is this login logic via RESTful call sound?

Raphael
  • 1,847
  • 1
  • 17
  • 29
smwikipedia
  • 61,609
  • 92
  • 309
  • 482
  • 8
    You should not let javascript on the client decide whether to let the user into the site. The client is not to be trusted. – Rolf Rander Dec 07 '15 at 13:16
  • @RolfRander Yes, when I changed to this *new approach* of login page, I felt weird, too. But I am not sure where it can go wrong. – smwikipedia Dec 07 '15 at 13:26
  • 2
    Ok, it is difficult for me to comment on specifics without seeing the actual code, but keep in mind that the user could change the clientside code before running it, and replacing the call to the login-function with a constant saying that the login is OK. – Rolf Rander Dec 07 '15 at 13:28
  • 2
    Definitely, a REST API must not depend on the HTTP session. Have a look at this [answer](http://stackoverflow.com/a/26778123/1426227) I provided some time ago. It will give you some inspiration on how to perform authentication. The approach uses tokens, but can be modified to cover other types of authentication. – cassiomolin Dec 07 '15 at 13:30
  • 1
    @CássioMazzochiMolin I agree with you. But why a `HttpSession` parameter can still be specified in a RESTful API signature? It seems Spring framework `permits` the use of session in RESTful API. Or is this just a side-effect/coincidence/mis-use of *Dependency Injection*? (Ref: http://stackoverflow.com/questions/26588310/how-to-create-and-destroy-session-in-spring-rest-webservice-called-from-mobile-c) – smwikipedia Dec 07 '15 at 13:41
  • 1
    As I mentioned before, *nothing* prevents you from invoking `HttpServletRequest.getSession()` and breaking the REST stateless constraint. The question you mentioned links [a good question about common REST mistakes](http://stackoverflow.com/q/544474/1426227). – cassiomolin Dec 07 '15 at 13:48
  • @RolfRander Actually, my client javascript did nothing but collect the input username/password and post it to server as JSON. The real authentication logic is done on server. The client side javascript essentially serves no more than a form submit button. Code is here: http://stackoverflow.com/questions/34146496/is-this-login-logic-via-restful-call-sound – smwikipedia Dec 08 '15 at 01:33

1 Answers1

157

Simply put: In REST applications, each request must contain all of the information necessary to be understood by the server, rather than be dependent on the server remembering prior requests.

Storing session state on the server violates the stateless constraint of the REST architecture. So the session state must be handled entirely by the client.

Keep reading for more details.

The session state

Traditional web applications use remote sessions. In this approach, the application state is kept entirely on the server. See the following quote from Roy T. Fielding's dissertation:

3.4.6 Remote Session (RS)

The remote session style is a variant of client-server that attempts to minimize the complexity, or maximize the reuse, of the client components rather than the server component. Each client initiates a session on the server and then invokes a series of services on the server, finally exiting the session. Application state is kept entirely on the server. [...]

While this approach introduces some advantages, it reduces the scalability of the server:

The advantages of the remote session style are that it is easier to centrally maintain the interface at the server, reducing concerns about inconsistencies in deployed clients when functionality is extended, and improves efficiency if the interactions make use of extended session context on the server. The disadvantages are that it reduces scalability of the server, due to the stored application state, and reduces visibility of interactions, since a monitor would have to know the complete state of the server.

The stateless constraint

The REST architectural style is defined on the top of a set constraints that include statelessness of the server. According Fielding, the REST stateless constraint is defined as the following:

5.1.3 Stateless

[...] each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client. [...]

This constraint induces the properties of visibility, reliability, and scalability:

Visibility is improved because a monitoring system does not have to look beyond a single request datum in order to determine the full nature of the request. Reliability is improved because it eases the task of recovering from partial failures. Scalability is improved because not having to store state between requests allows the server component to quickly free resources, and further simplifies implementation because the server doesn't have to manage resource usage across requests.

Authentication and authorization

If the client requests protected resources that require authentication, every request must contain all necessary data to be properly authenticated/authorized. See this quote from the RFC 7235:

HTTP authentication is presumed to be stateless: all of the information necessary to authenticate a request MUST be provided in the request, rather than be dependent on the server remembering prior requests.

And authentication data should belong to the standard HTTP Authorization header. From the RFC 7235:

4.2. Authorization

The Authorization header field allows a user agent to authenticate itself with an origin server -- usually, but not necessarily, after receiving a 401 (Unauthorized) response. Its value consists of credentials containing the authentication information of the user agent for the realm of the resource being requested. [...]

The name of this HTTP header is unfortunate because it carries authentication instead of authorization data.

For authentication, you could use the Basic HTTP Authentication scheme, which transmits credentials as username and password pairs, encoded using Base64:

Authorization: Basic <credentials>

If you don't want to send the username and password in each request, the username and password could be exchanged for a token (such as JWT) that is sent in each request. JWT can contain the username, an expiration date and any other metadata that may be relevant for your application:

Authorization: Bearer <token>

What might be wrong with your server

Once you have a session indentifier, I guess a HTTP session is being created somewhere in your application. It can be in your own code or in the code of the framework you are using.

In Java applications, you must ensure that the following methods are not getting invoked:

Community
  • 1
  • 1
cassiomolin
  • 124,154
  • 35
  • 280
  • 359
  • 2
    Thanks. So basically, if I follow the RESTful approach, HTTP protocol is my only friend. And yes, I am using the `HttpServletRequest.getSession()` call. It seems the technology itself doesn't prevent me from doing that (actually it kind of `lures` me to do that). I need to stick to the `discipline`. – smwikipedia Dec 07 '15 at 13:05
  • I add some background of my question. Appreciate if you can put some insight. – smwikipedia Dec 07 '15 at 13:15
  • @smwikipedia Regarding to your first comment: Unfortunately, **nothing** prevents you from invoking `HttpServletRequest.getSession()` in your application. However, if you use [JAX-RS](https://jcp.org/en/jsr/detail?id=339) with [CDI](https://jcp.org/en/jsr/detail?id=346), you'll realize the [`SessionScoped`](https://docs.oracle.com/javaee/7/api/javax/enterprise/context/SessionScoped.html) is disabled. – cassiomolin Dec 07 '15 at 13:19
  • Does "contain all necessary" data imply that the authorization info (e.g. claims) should also be stored in a token? Or is it ok to securely store only user_id in the token (e.g. JWT), and then the server can look up user permissions in a database based on this user_id alone (i.e. no other information required)? Or just retrieve them from cache for that value of "Authorization" header. – dan Feb 21 '17 at 19:40
  • 1
    @dinvlad It's up to you. Tokens can be _opaque_ (like a random string) or _self contained_ (like JWT). This [answer](http://stackoverflow.com/a/35316102/1426227) may also be insightful. – cassiomolin Feb 21 '17 at 19:47
  • @CássioMazzochiMolin, thank you! reading that now. In my understanding then, storing only authentication info such as user_id (but sufficient to determine authorization based on a database lookup) does not violate statelessness, is that correct? – dan Feb 21 '17 at 19:53
  • @dinvlad Yes, you got the idea :) – cassiomolin Feb 21 '17 at 20:08
  • 2
    @Cássio Mazzochi Molin, nice - I think I understand it a little better now: stateless here really means that every connection is "new", in a sense that we don't have to "prove" to the server that we initiated a session in a prior request (such is the case with cookies). It becomes impossible to "break" a "session" between different requests because there's none now. – dan Feb 21 '17 at 20:19
  • 3
    @dinvlad Exactly. In a RESTful application, there's no such thing as a session on server side. When targeting a protected resource, the request must carry the credentials to be authenticated/authorized. A common approach to secure REST applications is the _basic authentication_ over HTTPS. In this approach, the client must send the username and the password in each request, then the server can perform the authentication/authorization. – cassiomolin Feb 21 '17 at 20:47
  • 3
    @dinvlad In an authentication scheme based on tokens, the token becomes a credential of the user. Hard credentials such as username and password are exchanged for a token that must be sent in each request then the server can perform authentication/authorization. Tokens can be valid for a short amount of time, can be revoked, can carry scope details (what can be requested with the token), etc. – cassiomolin Feb 21 '17 at 20:53
  • How prevalent are pure RESTful ("know nothing about the client") applications? I can imagine that traversing graphs (nodes being identified by URIs), modifying graphs, uploading or downloading isolated resources fit the REST pattern well. However, once you get into the situation where transactions over sets of resources have to be effected, you have to go beyond REST. Already data transfer efficiency (if larg-ish intermediate results have to be pushed back and forth) and considerations of security (what has the client done recently?) break this approach. – David Tonhofer Jun 29 '17 at 20:35
  • 4
    Doesn't any application with a database mean it's not stateless? Where do you draw the line between what makes a request stateful? Unless your app is simply pure functions, it must be storing and retrieving data from somewhere, and thus the inputs do not fully determine the outputs. How is session state any different? It's just another type of application state that pertains to what the current user is doing. – jam40jeff Oct 16 '17 at 18:10
  • 1
    @jam40jeff This [post](https://ruben.verborgh.org/blog/2012/08/24/rest-wheres-my-state/) may shed some light on it. – cassiomolin Nov 08 '17 at 09:37
  • That makes sense, and is pretty much how I think about the separation already. However, I think that some functions can blur the line between the two. The knowledge of user sessions is IMO one of those things based on the needs of the application. If a user can only be logged in from one location, for example, the server needs to keep track of user sessions. – jam40jeff Nov 08 '17 at 19:38
  • 1
    one important point ; api being stateless does not mean you should move all the state to the client with state management tools like redux or ngrx. that is very wrong. state is bad. state is bugs. rest gets rid of the state for very valid reasons. so should the client. rest gets rid of html and css and js in http traffic so that the client can make abundant requests. if performance is issue, use caching not state management. use client state only for client (application) logic, not for caching data. keep dependency on a state at minimum. keep state local not global. – aycanadal Apr 10 '21 at 08:20