How to have a notification of expired Facebook user access token - javascript

I've seen a lot of examples, and read some articles to know well about the access token expiration and it was explained pretty well in this article, Access Token Expiration.
I know how to renew the expiration access token. However, the problem is that, as explained in the article, there are possibly 4 reasons for expiration of access token .
Hence, there is no certainty when the access token will be expired and it can be at anytime. The conventional solution is by using offline_permision which will be deprecated by FB soon.
Here is what I'm trying to achieve:
Once the access token expired, and while when user is using our facebook app, I want FB to notifies me.
Once receiving notification, renew the access token.
I don't think the following achieves what I want.
FB.Event.subscribe('auth.authResponseChange', function(response) {
alert('The status of the session is: ' + response.status);
});
Hence, is there any way to have notification from FB when the access token is expired ?

When you try to access the API with an expired token, Facebook will send back an error message. You just check for that error in your callback function that handles the Facebook response, and if an error exists, refresh the token and try the API call again.
From Facebook:
Facebook doesn't notify you that a previously issued access token has become invalid. Unless you have persisted the expiry time passed to your application along with the access token, often the first your application knows that a given token has become invalid is when you attempt to make a request to the API.

Related

Node.js — Google OAuth 2.0 for Web Server Applications -> How to use the token event

I'm trying to figure out how to use the token event as specified in Google's OAuth 2.0 documentation for server side applications (using Node.js):
Here's the code for the token event:
oauth2Client.on('tokens', (tokens) => {
if (tokens.refresh_token) {
// store the refresh_token in your secure persistent database
console.log(tokens.refresh_token);
}
console.log(tokens.access_token);
});
I actually get this event to fire, but am unsure about when to check for a valid token. If I do this one every request (let's say Google Docs API request), the token event fires after I'm requesting the API, so credentials are not set correctly.
How would you go about making sure that the correct access token is set BEFORE making a request?
Google says "Once the client has a refresh token, access tokens will be acquired and refreshed automatically in the next call to the API.", which is also kind of the case, but too late.
So my question once again: How do I, in my call, wait for the token event to finish updating my access token in order to set credentials BEFORE making the request?
Thank you!

Best way to check jwt token expire status if stored in localstorage

I want to check if the token is expired on client side.
My token is stored in localstorage.
Now what I do is: make a call to the server to check if it is valid but I only do it when the path is: https:exp.com/
code:
useEffect(() => {
verifyToken(auth.token).then((res) => {
if (res.status !== 'success' && res.message === 'Token expired') {
signoutClient(() => {
router.push('/auth/login');
});
}
});
}, [auth.token, router]);
Now the problem here is what if the user goes directly to another url exp : https:exp.com/helloworld
I was thinking to use sockets but I don't know if it could work.
Idea is: client stays in listen, whenever token expires server emits a message.
Any idea on how can I do it?
There are different techniques.
Note that handling time on two different machines (expiration in this case) may lead to issues due to time jitter or clock misalignment, so it is not so straight forward
Passive expiration
My favorite pattern is to have a dedicated server error.
Your server should respond with a particular error when the token is expired (to be distinguished from the 401 Unauthorized due to role access). You then add an HTTP middleware to your client that:
detects this error response
deletes local token and navigates to /auth/login
Or if you have a renew token:
detects this error response
attempts to renew the JWT
repeats the original request on success OR navigates to auth page on failure.
This is a passive system that allows you to treat the JWT as an obscure string and does not have time-related issues.
Return a separate field
If, for security reasons, you want to hide sensible information when the session expires even when the user is not interacting with the UI (like Banking sites do) you need to know when the token will expire. A common technique is to return expiration time together with the token (within the authentication response).
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.JFDV4mOKKh0sMfkBKvsbvm8iWjHEGBXtPvC49ob3qiI",
"expiresAt": 1234567890
}
Or even better
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.JFDV4mOKKh0sMfkBKvsbvm8iWjHEGBXtPvC49ob3qiI",
"expiresIn": 600
}
The first one returns you the UNIX time of token expiration relative to server time. This is subject to time jitter or clock misalignment (this may lead to errors). The second one is better as it lets the UI know within how many seconds (since the Response was received) the token will expire, this can be then used to calculate the UNIX time according to the local clock.
It is common to remove a small time step from expiresAt and expiresIn to avoid clock jitter and clock drift issues.
Parse the JWT
If you have no other solution, you can always parse the JWT:
const JWT = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEyMzQ1Njc4OTAsIm5hbWUiOiJKb2huIERvZSIsImlhdCI6MTUxNjIzOTAyMn0.1c_yQjnMZfKUb4UTDE_WvbC71f8xxtyMsdqKKkI1hF8`;
const jwtPayload = JSON.parse(window.atob(JWT.split('.')[1]))
console.log(jwtPayload.exp);
You can use a lib(like jwt_decode) to decode your JWT token, where it's most likely contains an expiration timestamp that you can check(compare it with the current timestamp for this moment) and if it exceeded(expired) just delete it from local storage and redirect user to login page.
But you also have to consider add a catch block for functions which calls your API to check for any 401 response status code to also do the same (in case the token was valid then while the user is moving around its expiry date ends)
If you are using the Axios library, you can use the interceptor to check the token expiration thus you can put in a request that handles the retrieval of a new fresh JWT token from the backend API.

JWT: handling token auth on a multi-domain-level

Currently I'm facing the following problem:
I'm building an application with a standalone login view.
Let's assume they both run on different domains. My login view communicates with a REST service on the server that issues a JWT token.
With this issued token the user should now be able to view (be forwarded to) the application. But this application - as mentioned - runs on another domain (or subdomain, maybe).
In my mind I tried the following:
Token is issued by the server. A hash is stored in a database and the hash is issued to the user. The hash is transferred to the application via URL and the applications checks the hash.
Token is issued by the server. The token is transferred to the user. When the user now opens the application (or is forwarded to...) the token should be transferred there, too. I have no clue how to do...
Both are not ideal ways, i know. But I really don't know how I can achieve that...
I hope anyone is able to help me with my thinkings?
If anything is unclear, just comment.
Thanks in advance!
Facebook, Twitter, Google, etc. offer OAuth by redirecting (302 Redirect Request). Basically your app starts if user has a valid token everything is fine, else it will open the Login-Page from the Identity Provider (e.g. Google) and return the token, if the login was successful.
This graphic shows the general steps:
https://www.soapui.org/soapui/media/images/stories/oauth2/oauth2flow.png
Hope this helps.
Lets assume you have two services in 2 different domains. One is your identity provider which generates tokens and holds the token <--> user assignment (we call it: idp.my.company). The other one is any application that does stuff but needs to login via idp.my.company (we call it app.my.company).
You have two scenarios:
1. Login without having a token aquired before.
2. Login with token.
Request GET: app.my.company
Response 302: Moved to: idp.my.company
Take a look which redirection type follows your needs (307 maybe)
https://en.wikipedia.org/wiki/URL_redirection
You need to add an information where to redirect back. In this case app.my.company.
[This happens automatically because of the Redirect] GET: idp.my.company/login.html.
Response 200 OK: idp.my.company/login.html
The User will now see the Login-Page of your IDP-Service and perform a Login.
Request POST: idp.my.company/login.html (or whatever)
The User posts his credentials to aquire a token
Response 302 Redirect: If login is successful, return token and now redirect to the origin site (app.my.company) which you provided earlier.
Request GET: app.my.company/afterlogin.html
The header contains a valid token
Response 200 Ok: Now the app.my.company service needs to check if the token is valid and if true return 200 Ok otherwise redirect again to IDP (start over at step 2).
This should be it. There could be errors but you should have a consistent picture of the process and get a grasp on how to implement it. Those steps cover scenario 1 and 2.

Get amount of likes Facebook

I always used this URL(https://graph.facebook.com/[PAGE-ID]) via JavaScript to get the amount of likes, but now I get an error:
"An access token is required to request this resource."
Is there another possibility to get the likes without an token?
Can I set my access token directly into the request (security)? Is the token a secret token?
I've found a solution to get it without a token. I can use the following URL:
https://api.facebook.com/method/fql.query?query=select%20fan_count%20from%20page%20where%20page_id=[PAGEID]&format=json
No, you have to use a Token. But you can use an App Access Token that does not require authorization.
You should always keep any Token secret, only use it on the server.
You cannot get it without token. Read more about how to generate tokens here

Comment on Facebook page posts as page owner with extended token

I'm developing a node.js app which manages a Facebook page among other functionalities.
To comment on user submitted posts, I use the following code in node.js:
FB.api(object + '/comments','post',
{ message: COMMENT_I_WANT_TO_SUBMIT, access_token: MY_PAGE_ACCESS_TOKEN },
function(res){
// deal with res
}
);
When using my short-lived Facebook page access-token (which I get from Graph API Explorer) the comment submitted is shown as a comment submitted by the page itself (what I want), but when I use my permanent token it is shown as submitted by myself (page owner).
To get this permanent token I followed these instructions:
https://stackoverflow.com/a/28418469/4713311
The token has my name associated to it since I had to grant permissions to manage the pages I own to generate the token.
I believe this token has the proper permissions since the token debugger shows the following permissions in scope: "manage_pages, publish_pages, publish_actions, public_profile"
Is there any way I can use this never expiring token to comment on posts with the page name instead of my own?
A Page Access Token should have not only "User ID" but also "Profile ID" associated, which wasn't the case for the extended page access token.
A Page Access Token isn't "extendable", to get a permanent page access token I had to request one with a permanent User Access Token, as explained here
Using as short-lived access token I got from Graph API Explorer (Select App -> Get Token -> Select permissions manage_pages, publish_pages, publish_actions and other you may need -> Grab the token that fills the "Access Token" text box) I made the following call to extend the token.
https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token&client_id={app-id}&client_secret={app-secret}& fb_exchange_token={short-lived-token}
Using the token returned, you can simply call /me/accounts and copy the page's access_token
This token is a permanent Page Access Token, to confirm you can use the token debugger and verify it has your "User ID" and your page's "Profile ID"

Categories

Resources