I have written a HTML 5 application that uses AngularJS and interfaces with a Java REST backend running on Tomcat. I use Spring Security to handle login and security.
When the user enters the website he is forwarded to a login page which creates a session and redirects to the index page. The REST calls that loads further data from the server then uses that session to authenticate. If there is no session in place, I fallback to basic authentication over HTTP, such that it is possible to invoke the REST endpoints separately from the web application.
The problem I have now is when the session expires. This causes a HTTP 401 Unauthenticated
response from the server. I thought I can catch that error and redirect the user back to the login page with Javascript. However before my error handler is called, the browser first shows a login window, only if I click cancel my Javascript error handler can handle the response.
My question is, is there a way to prevent the browser from showing this login window? Or is this a general problem with my application design?
The alternative might be not to use a session at all and to cache username and password in the application. Then I need to send it with every REST call using basic authentication, would that be a better approach?
The following is the HTTP response from the server:
HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
WWW-Authenticate: Basic realm="Spring Security Application"
Content-Type: text/html;charset=utf-8
Content-Length: 999
Date: Mon, 30 Sep 2013 11:00:34 GMT
Update: It appears that the reason for this is the WWW-Authenticate
header, which causes the browser to display the login dialog.
If you want to avoid changing the server and make it return
WWW-Authenticate
header for all other callers, you can change your client to send its request withX-Requested-With
header withXMLHttpRequest
value. By default, Spring Security will not to sendWWW-Authenticate
for such requests. (see Spring source)I finally found the solution for this. As I mentioned in my update the reason is, that the response contains the
WWW-Authenticate
header field. My solution was then to change the configuration of spring security to return a different header:To do this I had to implement the
AuthenticaitonEntryPoint
interface and manually set the header and status code in the response:then I changed the configuration of spring-security and set the
entry-point-ref
to point to the new class: