The correct solution is to issue the redirect regardless of the status of the target URL if the user is not authenticated. This is easily doable for any normal web server (you set up a redirect rule to match on the common prefix for all the sensitive pages that also checks for the existence of the session credentials), provides good UX for legitimate users, and avoids the issue of potentially disclosing the existence of specific URLs.
Note that when I say ‘redirect’ here I mean sending a 302 status code (not a 301 like some of the other answers suggest, a permanent redirect is not correct here) with a Location
header pointing at the login page, and ideally set things up to return the user to the desired page after login. This method avoids sending the login page if the client doesn’t actually follow the redirect, and also allows the login page to be cached (unlike doing silly things like URL rewrites or having the web app throw up different HTML depending on the authentication status), which should mitigate any usage issues from people trying to do URL harvesting.
If you really do not want to redirect to a login page, then you should return a 403 status code for all unauthenticated requests instead (and possibly use a custom error page with a link to the login page). This is the HTTP equivalent of a ‘Permission denied’ message, so unlike a 404 it accurately describes the actual error.
The important thing here is that regardless of which status code you choose, you return it uniformly for all secure URLs when an unauthenticated user attempts to access them. By making the response uniform, you avoid the risk of information disclosure, and it just comes down to how you want to respond.
What I describe above is the standard approach in most modern web apps when the default assumption is that the resource the user is asking for actually exists. If, instead, the default assumption is that the resource does not exist (this is the case for example with GitHub’s handling of private repositories), then the more correct behavior is to just return a 404 for all private URLs for unauthenticated users.
404 Not Found.
"