How can I use HandleErrorAttribute to execute action retry logic? - asp.net-mvc-4

I want to extend HandleErrorAttribute to globally handle a custom error type in my project. This what I was envisioning
Page user makes a request to pull a report from the site
The site (mvc project) needs to talk to a web api using an auth token
The api returns 401 with a body that contains an app code indicated it was because the token has expired
The site sees this and throws a TokenRefreshException
The site handles this globally by retrieving the refresh token from the session and using it to update the user's tokens, save it back to the session and then reattempt the action.
If it isn't able to refresh the token, it kills the session and redirects the user to the login page.
Is this possible and how do I implement this logic without creating an infinite loop (I'm not sure how to keep count)?

Related

auth0 still auto-logs in seamlessly even after calling /logout url

Simple problem, I want to login and out of an app with various users to check different app functionality. App is using Auth0 for user management.
I am calling the /v2/logout url as a part of my flow.
But somehow, after logging out, when I login again the seamless SSO behavior runs and I'm immediately logged in again with no prompts -- it's as if the logout URL was never called.
Only way to get a login prompt again, is to clear my browser cache. Is there an auth0 cookie somewhere I need to delete as well? Or am I missing something? I'm reading the seamless SSO docs but don't see anything beyond calling /v2/logout.
Calling the Auth0 /v2/logout API endpoint will log the user out of Auth0 and optionally the IdP (if you specify federated parameter). It will not log out the user from your Application so you will need to implement that in your application.
Here in the Javascript SPA example, in the setSession() we are storing the Access token(along with its expiry) and the ID token in localStorage. In the logout() function we are then removing these entries. This is logging out from the Application user session. You can optionally redirect to /v2/logout to clear the Auth0 and IdP session as well in this function. That way, when you are checking if user is authenticated, the isAuthenticated() returns false and we force the user log in again.
So turns out, the issue is around redirecting the user as opposed to calling the logout url directly. I was using a separate ajax api call to the logout url. However when I use window.location.replace(logoutUrl), the logout actually happens.
From the auth0 docs:
To force a logout, redirect the user to the following URL:
https://YOUR_AUTH0_DOMAIN/v2/logout
Redirecting the user to this URL clears all single sign-on cookies set by Auth0 for the user.
So a separate call doesn't work -- have to redirect. Which I suppose makes sense -- a separate ajax call doesn't have the user session context.

JWT Refresh token and Multi-Page Application

I am going to implement JWT authentication for several independent services.
There will be auth.example.com and service1.example.com, service2.example.com etc.
My assumptions:
JWT can be kept in cookie for ".example.com"
JWT expire time should be small (like 15 mins) because there is no reliable way to logout user with JWT token (revoke token).
Refresh tokens should be used to reissue JWT tokens
Refresh token cookies should be accessible only by auth.example.com for security reasons and because https://www.rfc-editor.org/rfc/rfc6749#section-1.5 says
"Unlike access tokens, refresh tokens are intended for use only with authorization servers and are never sent to resource servers."
Next, if I have a service - multi page application (i.e. not SPA), where some URLs are called "traditional" way, not via Ajax and render HTML
based on some server side logic, which, of course, include checking of user authorization.
then, say, there will be an action service1.example.com/user/showpage
if (user.logged_in) {
render_some_html(get_some_data(user.login))
}
else {
render_anonimous_uses_page()
}
Problem is:
If site user close all site tabs and, then after hour or so, go directly to page /user/showpage (or maybe he
suspend laptop and wake it up in an hour and go to that page).
What if by that time JWT token will expire. Then to refresh it by Refresh token we need to make Ajax call to auth.example.com (because Refresh
token is stored only in auth.example.com cookie) and this is just unaccessible in server side rendering (that pseudocode that I posted above, it's server side, and it's just impossible to make client ajax call in the middle of execution of server code. it's just not applicable here). This way user will be considered logged out
on this stage.
Redirect could be one solution.. but what if site should work for anonymous out users too, and anyway looking for something better.
This problem not exists for SPA application, because before every Ajax call to internal API, it can check JWT and make call to refresh JWT token.
And question is: is this true that JWT in general should not (cannot) be used in Multi-Page (traditional) applications because of this issue? or there is good way to workaround this? or this is not a problem at all (users don't close tabs too often, or they expect site to log them out or redirect etc)?

ExpressJS and Firebase Auth, beginner queries

I am trying to learn ExpressJS, so I creating a simple website with login functionality...
I want to use Firebase for the accounts and database(Firestore)
My problem is that, Firebase Auth seems to be client-side only and the backend has no idea if the client is logged in or not...
I want to limit the HTML rendered to the client if he is not logged in, but I can't figure out how to check if he is logged in
I know that I can use
firebase.auth().onAuthStateChanged(function(user){
if (!user){
window.location.replace("/login");
}});
on the client side, that doesn't look "Secured" enough to me and I would like to do it in ExpressJS
On firebase documentation I found this about Verifying ID Tokens
but I don't understand first of all how would I send the token to ExpressJS and second, how would I send it before the request to a route is made...
You have to pass the ID token to your backend. You then verify the ID token as explained in https://firebase.google.com/docs/auth/admin/verify-id-tokens#retrieve_id_tokens_on_clients.
You pass the ID token in the request header if your application is a single page app everytime a request is sent.
If you are building a more traditional web app, you can set the ID token via a cookie and retrieve it and check in on your backend with each request. You have to do the following:
Proactively refresh the ID token by calling getIdToken(true) before the token expires. The token typically lasts an hour. You would need to refresh it before expiration and update the cookie so a redirect will still consider the user signed in.
If the user visits your website after a while (longer than an hour), the cookie would be expired, you would redirect to a temporary page where you set onAuthStateChanged and if the user is logged in, call getIdToken(), update the cookie and redirect to the intended destination, otherwise consider the user signed out.

Handle authentication in a Service Worker for a React App

I have a React app rendering client-side, in which I handle authentication the following way:
Upon loading, the app fires an AJAX request to the backend, basically asking whether the user's session is valid ;
It updates the app's state with the server's response ;
It renders the "/" route accordingly (the homepage if the session is invalid, a dashboard if it is valid).
(Maybe there are better solutions for handling this in front-end applications, I'm all ears if you have ideas)
This works pretty well, but introducing Service Workers into the mix and trying to turn the app into an offline-first progressive web app seems... complicated.
On the one hand, if I don't cache the "Am I logged in ?" request and the app is offline, the app will always render the homepage.
On the other hand, if I do cache the AJAX request, the users will eventually be shown an empty dashboard because their sessions will have expired and the server will be throwing 403s.
Is there a way to handle this effectively?
I solved my problem by taking a different approach: I now persist the state in localStorage.
This way, when the user arrives on the app, he is presented with stale data from his last visit. Meanwhile, a "Am I logged in?" request is fired in the background.
If it is succesful and returns true, the other AJAX requests get fired and fill the app with fresh data ;
If it is successful and returns false, the state is updated accordingly and the user redirected to the homepage ;
If the request is unsuccessful (i.e. the app is offline) the app keeps showing stale data from last session in the dashboard. We don't know if the user's session is still valid, but we can't retreive any data so it does not matter.
One way of doing it is adding a /verifyToken (assuming you are using some kind of token to validate the session) in your back-end api to check if the token is valid.
So you cache your session token. If the app is offline it shows the dashboard.
If the app is online, you fire a request to /verifyToken to check is the session is still valid. If it is then you continue to dashboard. If it isn't you redirect them back to homepage (or the sign in page).
Edit:
When your app is online, you can technically fire a request to any authorized route and check if the response was 403 (in case you can't modify the backend). If it is then you can send them back to sign in page.

How to refresh the LinkedIn Authorization Token

I have a grails application and I want to connect my user's account to their LinkedIn accounts.
So my steps are:
Have the user click on a button that redirects to:
https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id=MY_API_KEY&scope=r_network&state=SOME_TEXT&redirect_uri=MY_REDIRECT_URI
Then LinkedIn redirects to the specified redirect_uri and I get the authorization code as a parameter in the response. With that code I do a post to:
https://www.linkedin.com/uas/oauth2/accessToken?grant_type=authorization_code&code=MY_AUTHORIZATION_CODE&redirect_uri=SAME_REDIREC_URI_AS_BEFORE&client_id=MY_API_KEY&client_secret=MY_API_SECRET
That works like charm! I get the Access Token and I save it in the User domain class together with the expiration date.
Now my issue comes when I want to have a piece of code with the logic to refresh the Access Token before it expires to avoid having the user clicking on the button every now and then. I know of applications where you link your account to LinkedIn and never have to refresh the token again.
In the documentation: http://developer.linkedin.com/documents/handling-errors-invalid-tokens you can find a section called Refreshing Access Tokens that says:
Refreshing an access token is very simple and can happen without an authorization dialog appearing for the user. In other words, it's a seamless process that doesn't affect your application's user experience.
Simply have your application go through the authorization flow in order to fetch a new access token with an additional 60 day life span.
So how can I follow the same process describe above if it starts with a click of the user in a button.
I have tried doing a GET using he HTTPClient class from groovy like follows:
new RESTClient(accessTokenRequestUrl, ContentType.URLENC)
where the accessTokenRequestUrl is the same used above in the button href. This should eventually call my redirect_uri where I use the authorization code to request the access token but it never gets to that point.
I have tried using the RESTClient add-on for Firefox and it works ok but it doesn't if the call is done from within the application.
Any thoughts?
Thanks in advance!
Cheers,
Juan
If you use the Linkedin JavaScript API, then the access token will be automatically refreshed without any user intervention. Make sure inside your initialization string you set authorize: true so that refresh is seamlessly done as follows:
<script type="text/javascript" src="http://platform.linkedin.com/in.js">
api_key: YOUR_KEY_HERE
authorize: true
</script>