Server redirect to login url from AngularJs page containing # (hash) sign

Problem

I use Spring Security to deal with session timeout. My application also uses AngularJs.

I have the following issue:

If the session times out and a user issues a non-ajax request from an angularJs page to a secured url, Spring Security redirects me to the login url but keeps the part of the Url after the # (hash) sign.

Let me illustrate:

  • A user is located at /myapp/foo#!/bar
  • Session times out
  • User issues get request to secured url
  • User is redirected to /myapp/signin#!/bar

How can I avoid the #!/bar part from being added to signin page?

Edit: There is a slight mistake in the description above. The problematic use case is as follows:

  • A user is not logged in and tries and access a protected resource such as: localhost:8080/bignibou/curriculum/#/view/1 (by pasting this url in browser's address bar for instance).
  • They will automatically be redirected to the following Url: http://localhost:8080/bignibou/signin#/view/1

Notice the part including and after the hash sign is kept. Note that this has more to do with AngularJs than Spring Security as Spring Security does not include the hash sign (this is confirmed by the fact that the hash never appears in the network tab of chrome dev tools...)

Problem courtesy of: balteo

Solution

Rather than Angular, this sounds like the intended behavior for hash fragments on HTTP/3xx redirects, as implemented by most modern browsers (and IE9 onwards, I believe). There is a detailed explanation on the nuances here:

URL Fragments and Redirects

and the official documentation is here:

W3C URI handling - Section 4.1.

Edit:

In order to modify (or, in this case, remove) the fragment, you can leverage HTML5's history state. Try adding this to your signin page:

history.replaceState("", document.title, window.location.pathname + window.location.search)

For further information on the replaceState, it's pretty well documented at Adding and modifying history entries in the Mozilla developer docs.

The obvious caveat here, is what versions of IE you need it to work in. From a quick google, it seems like you are looking at IE10 onwards, so for earlier versions, you would therefore need something more rudimentary like:

window.location.hash = ""

which will remove the fragment but retain the #, but hey, it's IE.

As a composite solution, therefore, you could use:

if("replaceState" in history)
  //  proper browsers
  history.replaceState("", document.title, window.location.pathname + window.location.search)
else
  // fallback for ie
  window.location.hash = ""
Solution courtesy of: scarlz

Discussion

As Rob mentioned above, the hash is not being sent back by the server, it is simply being preserved by the browser.

You could however set your login and session expired URLs to `/login#' so that the server returns a hash in the redirect URL, thereby overriding any existing hash.

Discussion courtesy of: manish

This recipe can be found in it's original form on Stack Over Flow.