Globally catch ajax response code, refresh token and resubmit - jquery - javascript

I have a .Net Core2 webapi in which I have a user/pass authentication to issue a short lived jwt (5 min) which includes a long session revocable refresh token. When the jwt expires, the webapi checks if there is a refresh available and if there is, it returns the new token
On the client side, I want to place a global hook on any ajax calls to catch the case where a 401 is returned, but with a new token. This hook would simply reset the token and resubmit the request.
Is the best way to do this ajaxSetup? Example would be appreciated. Any issues anyone can see with this approach?

Related

UpdateToken() method does not refresh the access token

Need help with the below-faced issue in the implementation of Keycloak redirection in the flutter web application.
Flutter Package Used : keycloak_flutter | Flutter Package
The above package has used Keycloak JS adapter implementation. to achieve keycloak redirection in the flutter web application using the below reference.
Reference : Securing Applications and Services Guide
Describe the bug :
Using the package I am trying to refresh the access token by calling the update token method which makes the refreshtoken API request from keyclaok.js. but the request returns Status 400 Bad Request, then I checked the request in the browser tool(network tab), and the refresh_token is passed as undefined. I also tried to pass -1 as a parameter to the update token() which forcefully refresh the token.
access_token expires in 1 min
Expected behavior :
The update token method should refreshtoken if the access token is expiry.
Also Observed
Immediately after successfully login OnAuthLogout event is fired
the token expired event is not fired even after the token is expired
Thanks in Advance.

How can I safely implement my login routes?

I am currently making a login and registration system as a project for a website, but I am uncertain of how I can safely implement the routes/logic for it. Currently, in my client side code I send a fetch request to my login or register route, and do the logic there, and then send a JSON object back, which is manipulated whether there is an error or not, and I have implemented CORS and Header (Origin and Referrer headers) authorization middleware within my POST routes, so no external script can mass produce users/login [aka brute force]. Is there another safer and better way of handling this?
What you want to do is, to use either JWT or Session Cookies.
Algorithm ->
User visits the /login page
User enters user id and password
U send a fetch or Axios request to your servers POST API route
axios(`/<api_route_here>`,{
method: "POST",
headers: {
Authorization: `Basic ${btoa(`${username}:${password}`)}`
}
})
In the above code, we are encoding the username and password with base64 and then sending them back to the server with the Authorization header. username:password
Note: Make sure u are using an HTTPS connection
In the server u decode the Authorisation value from the header. Then create a hash of the password with username as its salt. Then query your database if the hash matches the user's password's hash.
We are hashing here to prevent leaking passwords in case of a database hack.
It is obvious, that you will store the password for the user using the same hashing technique.
If the query is positive then send a 200 response else send a 401.
In the Axios promise resolution check for the headers status code to figure out if the sign-in was successful
To prevent asking the user their password every time. U must use session cookies. i.e in step 4 if the password is correct add a Set-Cookie header property with a session token value. Store that session token to your database. Next time you API is hit, check for the cookie. if the cookie exists then check that session token with your database. otherwise, send a 401
To prevent route spamming, implement a captcha.

Checking token expiry on every request on the frontend

I am using JWT's to authenticate my API server. The JWT is issued by an external auth server (in this case keycloak) and have a typical expiration time of ~5 minutes (IIRC), the frontend should then use these tokens to make requests to the API.
I have been trying to check the expiry date of the token on the frontend, before making each request. If the token is expired, I use the refresh token to first get a new auth token then make the request.
The basic workflow is:
== Login ==
1. Get Auth token
2. Store expiry (exp) date (this is in UTC seconds)
== API Request ==
1. Check expiry date (isExpired = expiryDate <= Math.floor(Date.now() / 1000))
2. If OK => make request
3. Otherwise, refresh auth token and redo request.
Is it bad practice to check the date like this? What is an alternative method to ensuring requests succeed?
I ask because I have seen problems on some machines where the expiration check always returns false (it is not expired)...
The problem with relying with a frontend check is you have no control over the local time on the user's machine, which could be wrong.
A more robust way could be to make the request as usual and if the token has expired return an error message from the server. On each request, if the error message is received from the server, the client can then trigger the refresh process and then resubmit the original request with the new token.
The best way to handle that situation is that the front should only check if the expiry date set in the backend is expired or not. Usually the error return just like this {name: 'TokenExpiredError', message: 'jwt expired'}. If that is the case, then that's the time that you will make another login request.
I feel, a frontend check will be a good instead of making a request with expired token and do the refresh mechanism post that. I agree, the local time may differ. To make sure that it does work if we use UTC in token we can easily validate in any timeZone.

What is the best way to update the accessToken in the app with the new accessToken?

Before getting to the actual question
Alright I have created my own authentication system that I am going to use on my API.
Simple explanation:
On /signup the user types in username, password etc... the API grants the user with tokens which are stored in the user document in the database. The API also returns with a response body with the new refreshToken and accessToken, my thought here is so the app easily can store the tokens on the phone for later calls to the API.
/login is pretty much the same thing except you only provide username and password.
One of the routes in the API is the /article which you can GET & POST.
Now if you try to for example GET the /article and your accessToken is expired the API will automatically call /token which requires the refreshToken in the header, the /token will then grant you a new accessToken and request the same route you were trying to get (in this case /article) with the new accessToken in the header.
The question:
What is the best way to update the accessToken in the app with the new accessToken?
router
.route('/article')
.get(
AuthenticateController.authenticate,
NewsController.getAllArticles,
AuthenticateController.sendAuthorize
);
This is how I do it now, AuthenticateController.authenticate authenticates the accessToken and checks if it is expired and all that then calls next().
The NewsController.getAllArticles gets all the articles and also calls next() so the AuthenticateController.sendAuthorize can run and return the new accessToken in the response header when a new one is granted (I thought this would make it easier to obatin the new token in the app). This is where my question comes in because I can't call next() on every route because on some routes the main function already returns a response and that means that next() cannot be called which means AuthenticateController.sendAuthorize will never run. I want the AuthenticateController.authenticate to be the only middleware required to authenticate the user.
Instead of waiting until the last route to send the new token, you should move the sendAuthorize middleware above the route's main response (or combine it with authenticate), and instead send a 401 Unauthorized response with the new token. Then, update the token on the client and resend the request.
It seems like a silly practice to send a valid response with an invalid accessToken anyway. You're going to want to invalidate tokens eventually (I.e on log out or password change), and you don't want users to be able to make unauthenticated requests.

Check access token before http request

I'm creating an app using Angular 1.5.8 and Laravel 5.2. I'm using a library by Luca Degasperi to create Token Based Auth
Via Angular I make a call and I receive access_token, TTL and refresh_token. I store access_token and refresh_token on localStorage. I can use access_token that I get to make calls to get some data from my API. When token expires I'm getting a message that the token is invalid with 401 code
So my question is how to check if the token is still valid before I send a http request to my API? What is the best way to refresh the token? Ok, I can send a request for the refresh my token to https://my.api/oauth?grant_type=refresh_token&refresh_token=f32j93201h00xpaf1, but how to check it before every http request? Can I repeat the call if the response code is 401? And how?
Please, give me some advice :)
I had exactly the same problem few days ago. Angular Error response interceptor is all you need ;) Also, this article was really helpful
You cannot. You have to check against a login. Therefore it's just a re-login.
I guess that if you get a 401, your refresh token is already done.
Though I guess that you can join that refresh token with all your requests? I might be wrong.
Ensure that your token TTL is always up to date by refreshing its TTL from time to time (like with requests to your API).
Can't you use the TTL to determine if the token is still active? When you store your tokens in local storage you can add the date/time the token was stored and each time you go to make a service call you can check the TTL against the time the token was stored.
It will only tell you when it expires, though, and not if the token was invalidated for some other reason.

Categories