Handle authentication in a Service Worker for a React App - authentication

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.

Related

Is there a way for a SPA to check if there's a proxy and handling it properly?

We have developped a SPA SaaS and went to a soft production launch recently.
Everything was fine until one of our customers told us they had trouble using the app.
Once they open the app, the first request to our backend triggers their proxy credential prompt. Hopefully on the login request.
They have to enter their proxy credentials to let the request go. All subsequent requests are passing properly and they can use the app.
The problem is:
When they stop using the app, close the browser and then come back the day after, the persistent login tries to connect them to our backend, but the proxy credentials prompt is not triggered and the request fails. All subsquent requests fail also.
For it work again, they have to delete all app data in chrome (so the service worker is unregistered, the localstorage and cache are cleared). The next api call will trigger their proxy credentials prompt and they will be able to work again.
So is there any way for the app to know if the proxy is set or not ? Any way of triggering the proxy prompt if not set or whatever ?
I don't exactly know how those proxies work and we have zero access to the proxy settings.
It surely is something with the credentials expiration after some time but that's all we can figure out right now. Maybe we could monitor some params in the request headers ?
We are using VueJS with axios for the requests.
My guess is when user session credentials get expired, your UI is not handling redirection to login page. When the user login for the first time you should store that the user has logged in successfully in browser localstorage. If your server returns 401 error code, you can delete the flag and redirect the user to login page. You can achieve that using meta fields in router.
Check out this link on how to use meta fields https://router.vuejs.org/guide/advanced/meta.html

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)?

Issue with authentication using a LoginModule

I am encountering a strange situation with MobileFirst 7.1 where users are occasionally unable to authenticate/login. The only indication that something is awry is a message in the console.log
[AUDIT ] CWWKS1100A: Authentication did not succeed for user ID . An invalid user ID or password was specified.
My custom login module uses com.worklight.core.auth.ext.LdapLoginModule (so to clarify I have a login module which authenticates using LDAP). Like I say everything seems to work most of the time but occasionally users end up in a situation where they are unable to authenticate. I suspect that it is probably related to the session in some way, but that is only a guess based on my investigation.
I have added some logging to my 'secret' adapter which prints the session state to the console log, and obviously this appears in the logs just before the failed authentication message above, but it is empty ie. the session contains nothing.The user is obviously trying to access a secure adapter at this point, and because they are not authenticated they end up at the login page (form based authentication I should say also).
Anyway, I noticed that although there appears to be no session data, the jsessionid is there and has not changed i.e. it does not change even if I refresh the browser. This may not be an issue in itself of course, but interestingly if I remove this entry and refresh my browser I am able to login successfully.
I am pretty sure that my handler code calls the relevant success/failure methods in the correct places but of course there is nothing to stop the user refreshing their browser, which causes them to be re-directed to the login page (the app has been developed using AngularJS so is effectively a single-page navigation model).
The only reproducible test I have been able to come up with is when I login to the MobileFirst console and then try to login to our MF 'desktopbrowser' app. I have read that this situation causes a session-related conflict, but as I say the occasional issue I am seeing is not caused by this (though it may be related).
So the problem seems to have been more related to the flow of logic in our application after successfully logging in, than any inherent issue with the MF Platform.
For example when a user refreshes the browser they are effectively still logged in, but because the app (based on logic we have developed) takes the user to the login page on refresh, the user is effectively re-logging in to the same session. If this failed every time it would of course have been easier to pinpoint but it does not. The solution was to force logout on refresh (when the app initialises), thus cleaning up any session data. In future iterations it may of course be better to re-establish the application based on the authenticated session after refresh, but at present that was a step too far.
Another example of this was post login if the subsequent adapter calls failed (e.g. we authenticate and then retrieve profile data from a database), then we were also not logging the successfully authenticated user out.

X-CSRF-Token issue in ionic. Every time a different token is received

I have a backend with Drupal.
Using Drupal Services to interact with. Which provides a rest server.
Created endpoint named 'api'.
Following sequence works in normal browser or any http client like postman :-
example.com/api/login (works).
api sends back user data (token,session id, session name etc).
Further any request I make, I send token as X-CSRF-Token (all requests work).
I can even logout the same session with the token received before.
IN IONIC APP :-
I can login and I also store user data (token, session data etc.) in local storage after login.
Here's the difference in app :-
When I send the same token back to server while making a request (say logout).
Server's response is "User is not Logged In."
Why does this happen?
Update :-
After logging in I tried getting the current token from the server, and it was different from the one I saved after successfully logging in.
Every time a different token is received.
I faced the same issue. Problem was i never set the cookie and chrome did this for me automatically.
Luckily i found this great site:
drupalionic.org
There are links to a view demos as well as good descriptions and code.
So what you have to do is:
- log in
- retrieve session data and set cookie
- perform subsequent requests with the cookie data and X-CSRF-Token in your header
Here is a flowchart:
Was this helpful for you?

How can I use HandleErrorAttribute to execute action retry logic?

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)?