In a "standard" web application, if a user requests a page and their login session doesn't exist or has expired, they get redirected to a sign in page.
In a more dynamic web application where all the updates are done via AJAX and full page loads are rare, something else needs to be done. Handling a 302 redirect status code with jquery is possible, but it takes just as much (or more) code as any other status code. When developing the next web interface for StatHat, we made the server code as dumb as possible. It doesn't know what the interface wants to do if the user is not signed in: it could redirect to a sign in page like the original version, it could show a modal dialog, whatever.
403 Forbidden is often used. But look at the spec:
The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.
It clearly states that authorization will not help. The other main contender is 401 Unauthorized:
The request requires user authentication. The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field (section 14.8)...
This sounds perfect except for the WWW-Authenticate junk. We aren't going to support HTTP basic/digest authentication, but it seems like we are still honoring the intention of the spec to use 401, so we we went ahead with it and just ignored the WWW-Authenticate part of it.
We could have created our own error code, but that's breaking the spec even more.