I'm learning making API Requests from a mobile app.
An API that I am using, returns an access_token, expires_in and refresh_token when making a login request.
I'm trying to understand the whole logic behind the access token idea, been looking all over the internet and cannot find a good example nor a good explanation.
As far as I am aware,
The best method for making API requests is:
1) Store the expires_in internally on the device
2) On every request first check if the token is expired
3) If so, then request a new one using the refresh token
4) Otherwise make the request
Is this right?
Your flow is basically correct.
If it is a JWT token, you can decode it. Inside you can find some properties, check here.
What you can do is use the iat property of the token, this contains the time when the token was issued (you can't rely on the received date from the WS) add the expiration time to that date, this will be the expiration date.
If you are using Alamofire is pretty easy, there are 2 protocols:
RequestAdapter
RequestRetrier
By using a combination of the two can you easily refresh your token, in the request adapter you can throw an error if the token is expired, in the retrier you can intercept this specific error and make a refresh token request.
It is explained here.
Related
I'd like to implement a Facebook authentication that does not perform traditional oauth redirects. It doesn't play nicely with my single-page-application and GraphQL API.
On the JS side, I can invoke FB.login to trigger a dialog for the user to login. If this is successful, I receive an object containing an accessToken and a signedRequest.
signedRequest can be decoded on the server and it spits out a code for me. I can use code with /oauth/access_token to get an accessToken.
However, I already had the accessToken this whole time from the FB.login response. So my question is: is there any point of me decoding the signed request, if I had the access token this whole time?
Bonus: Why does the FB API provide a signed request in the first place, and why does the oauth redirect by default forward the code and not an accessToken?
Yes, you can use the token you got from the client-side login, directly on the server.
It might however be a short-lived one, whereas the server-side login flow should give you a long-lived one right away. If you only need to perform API calls while the user is active on your page, the short-lived one will probably do. (And it could still be exchanged for a long-lived one with a server-side API call, https://developers.facebook.com/docs/facebook-login/access-tokens/refreshing)
Why does the FB API provide a signed request in the first place
It also contains a bit more info, that might be useful for a client-side app (user id, token expiry, externally passed in data in case of the old “Canvas” type apps), and might save on one additional API call to get that kind of info. https://developers.facebook.com/docs/reference/login/signed-request/
and why does the oauth redirect by default forward the code and not an accessToken?
General security measure. The token contained directly in the return URL, could easily be stolen by 3rd-party scripts that might be embedded on that page (ad servers etc. can get hacked from time to time, too), or leaked as part of the HTTP referrer.
The code parameter requires your app secret for the API call that exchanges it for a token, so if the code were to leak in any such way, whoever else got their hands on it, can’t do anything with it.
I’ve been spending hours and hours on this, this is the first time I am using JWT and would really need some of your thougts.
Right now I store my tokens in separate httpOnly cookies (my access token expires after 15 min and refresh token after 7 days).
I have read that the most secure way to store the tokens is actually using a cookie for the refresh token and in-memory (like in a variable) for the access token.
While I understand this is secure, I do not really understand how it would work in practice. Would it mean that we have to create a new access token with our refresh token on each request? Or is there a way we can make it valid and copied to new variables until it is expired?
I am using react and node btw.
I spent days reading about this too.
From what I gathered a solution would be something like this:
User logs in with login and password.
Server generates a refresh token long lived to be stored as an HttpOnly Cookie, preventing XSS attacks as it can not be accessed by Javascript.
Ideally some sort of blacklist can be used server-side to prevent re-use of refresh tokens that have not reached their expiry but have been replaced.
Generate an access token which can either be stored in localStorage or in-memory (in a variable). The access token has a short expiry life of a few minutes.
If stored in localStorage, the token will not disappear on a reload of the page/browser (F5). It will also be visible in the console/storage.
When using localStorage to check if user is authenticated, the code will try to read the token from localStorage, jwt_decode it and set a user variable with the data that is in the token.
As tokens are not encrypted, just base64, their values can be changed in the dev console. A page that is "role: admin" only will be rendered if the permission is changed. The API will be responsible to check for permissions and reject the request if the token has been tampered.
Afaik, if it is stored in a variable it is a little less visible, it also gets wiped when reloading the page/browser.
When using a variable, to avoid refreshing the access token on every request, we can use the Context API, by creating a Component with the authenticated user context that will wrap the App/Router and then on every page that needs to be protected import and use this context and redirect if needed.
When the access token is not valid anymore, because it has reached its expiry, or because it has been wiped, the API call will get rejected. Intercept this call then call the API refresh route to use the refresh token to generate a new access token.
I use axios with axios interceptor to intercept the failed request, call the refresh route, set the renewed access token, then retry the failed request. (needs to be a GET request to avoid CSRF errors apparently).
In addition (not in place of), a setTimeout can be used to automatically refresh the access token every X minutes to prevent letting it expire.
To log out, remove the cookie (eventually blacklist) and wipe the context / localStorage.
Using axios, axios.defaults.withCredentials = true; makes sure that the cookie is sent with the requests and { headers: { 'Authorization': `Bearer ${access_token}` } } makes sure the access "bearer" token is sent with the request. These can either be set as defaults for every request or per request hence these 2 syntaxes.
Github example with Flask and React
I have a question on "make the browser send out a request to exchange for a new token at the sixth day. Accordingly, on the server side, create a restful API named /token/extend which will return a new token if given a valid token."
Let's assume that I implement this concept. When token is about to expire, we will generate new valid token if old valid token is provided.
Now, let's assume, Hacker gets the token. He uses this token to communicate with APIs. Hacker communicates for 6 days. On 6th day, our "/token/extend" API will generate new token for him so he can communicate for another 6 days, and probably forever. Will this situation occur? or Am I missing something here?
The general way you would force your users to obtain a new token after 6 days would be by simply setting the exp field (expiry) in the claims of the JWT to expire after 6 days. The exact mechanism by which users would use to obtain a new token depends on your implementation.
The most basic implementation would be to just let the incoming request on the sixth day to fail, forcing the consumer of the API to redirect to the login page. From there, the user would have to login again to obtain a new valid JWT. A more elaborate method would use refresh tokens. With this approach, when the user first logs in, he would receive an authentication token with a 6 day expiry (as before), but would also receive a refresh token which would expire a little bit later. On the sixth day, when the user tries to access a service, the request would again fail. However, in this case, the consumer (e.g. a website or mobile app) could take the refresh token and request a new access token under the hood. This would be a more seamless way of handling the mandatory 6 day expiry. Note that with the refresh token approach, the user might never know about the 6 day expiry.
Regarding your concerns about hackers obtaining other people's tokens, you should mostly just forget about this. If someone stole your wallet, there is all sort of havoc he could do to you, e.g. using your credit cards, stealing your identity, etc. The same could happen with a stolen/sniffed JWT. The best practice here is to just make sure you are using two-way SSL for all communication, and also encourage your users not to use your services in places like Internet cafes.
So this is a random question that I can't seem to see an answer to.
I'm using Token based auth in my application. When the login credentials are first sent to the system, a token is returned. That token is then required with each and every request afterwards. When the token expires, a refresh token is used to determine if a new one should be issued. All pretty basic stuff.
What I've noticed is that the token isn't returned to the client with each web call. As in, client sends a message to the server with the token, server sends a response, but doesn't include the token unless it has been refreshed. Now, obviously thanks to client-side storage the token is still available.
My question is whether or not it is a best practice to return the token with each and every response, even if it is unchanged. Or if this really isn't a big deal and I can just stop worrying about it.
Thanks in advance.
Generally no, the response should not contain the token as it's unnecessary at that point - the user has already been authenticated for that specific request and appropriate actions have been taken (either a 200 with data or 401 or whatever).
It is the responsibility of the client to know the token when making a request.
I just touch with RESTful API. Basically, no matter what the rest api is, the first step is to get access token. However, I have been in two different situations:
Have client_ID, Client_secret, and username, password.
POST: api.XX.com/1/authorize?
Authorization:Basic [client_id:client_secret] must be base 64 encoded
Content-Type: application/json
Then, I get access token without timeout.
Have app_key
GET https://api.XX.com/authorize?
response_type=Pin&
client_id=APP_KEY&
scope=SCOPE
After get Pin, register in web application. Then use code to request access token.
POST https://api.XX.com/token?
grant_type=Pin&
code=AUTHORIZATION_TOKEN&
client_id=APP_KEY
Finally, I have access token and reflesh token. access token will be timeout after 1hr.
So I need to use refresh token application access again.
I just want to say, Even the RESTful doesn't have Standard, access token application methods are big different. I think the first one is better. The first one makes things simple.
Because I just start to call RESTful Web Services, I would ask:
Are these two authorization methods common way? Is there a third method to get access token? Any comments please. Thanks.