-
Notifications
You must be signed in to change notification settings - Fork 350
Support for new Facebook endpoint to extend access token lifetime #57
base: master
Are you sure you want to change the base?
Conversation
…ific extension which allows the user to request a long-lived access token given that he has a short-lived one
See my comments on the other pull request you submitted. Also, I already have a similar piece of code in place in a local branch that does not require any changes to Spring Social Core. But as I said in the other pull request, the endpoint can only be used for client-side extension of token expiration. As for this someday becoming part of the OAuth standard, I have serious doubts. The OAuth 2 spec isn't final yet, but it also hasn't changed dramatically since around draft 14 and I believe it is inching closer to being final. Adding something like this would no doubt disrupt that specification process, further prolonging finalization of the spec. Furthermore, the OAuth 2 specification already defines the notion of refresh tokens which solve this problem in a cleaner way than what Facebook has come up with. It's unfortunate that Facebook is not implementing the refresh token portion of the specification that Facebook itself is helping to write. I suspect that the odds are greater that Facebook will implement refresh tokens before the OAuth 2 spec will define Facebook's approach. But time will tell...until then, I'm not eager to add anything to Spring Social Core to directly support anything provider specific such as this. |
Thanks for the input, I appreciate it. My interpretation of what's going
How they're doing this is to have a client-side flow with short-lived To get a long-lived access token via the server side flow requires either The bad news is that this is all theory so far :) I've been looking at Thanks for the prompt response. As I develop the TangoMe Facebook John On 5/11/12 8:01 AM, "Craig Walls"
|
Regarding point #3, I see nothing wrong with "unbounded refresh", when it is, in fact, not unbounded. The user may at any time revoke access and shutdown the refresh. My problem with doing a refresh at the browser-level (via the authorization flow) as FB requires it is that you may not realize that you need to refresh until you're deeper in your application code. A per-the-spec refresh token would allow the server-side code to put its work on hold, refresh the token, then carry on. But browser-refresh will require a lot of special handling to keep the application flow uninterrupted. My other problem with doing a refresh at the browser level is simply that it is not how it's defined in the specification and therefore I must have special-case code to cover FB's non-compliance with the spec. Your thought on letting a client get the short-lived token and then allowing a server to refresh from that is a valid one and I had thought of that scenario. I'll consider it some more and decide how I want to proceed. It kind of demands that there be an example of that to showcase it, though...as well as some very clear documentation indicating that you shouldn't expect a long-lived token to be extended any further. I wonder, however...FB's docs say two conflicting things: (1) You can only extend short-lived tokens, not long-lived tokens and (2) you can extend the life of a token every time the user visits your up, up to once per day. So, if you can only extend short-lived tokens, how can you continue to extend the life of a token once per day if the only token that will survive into tomorrow is the long-lived token? And, what happens if you get a short-lived token, extend it to a long-lived token, and then the 60-days is almost up? The short-lived token is no longer any good and you can't refresh long-lived tokens. Therefore you're going to have to go through the authorization flow again anyway. And, it's unclear on what FB means when they say "client-side". I interpret it as JavaScript code, but others interpret it as mobile (iOS/Android) code. It may even be that both are true. But if there's any truth to the JavaScript part of it, then how would a client extend the life of a short-lived token unless it either relies on the server to do it or if it carries the secret in the JS code. |
This wasn't what I had planned to work on today, but...since it is a hot topic and will become more important as we approach July 5, I thought I'd give it another look. I've done another sweep of tests and confirmed that the initial token granted to the server side is a long-lived 60-day token. I've also confirmed that calling the aforementioned endpoint with that token does nothing to extend the life of it. (Of course, I really should try again tomorrow to be certain that I'm not just hitting the once-per-day rule...but I have confirmed this in the past.) As I mentioned before, no matter how you end up with a long-lived token (client or server), you're going to need to freshen it up before the 60 days is up and the only way to do that is to go through the authorization flow again (because you can only extend the life of short-lived tokens, not long-lived tokens). Fortunately, this doesn't bother the user because as long as the user has not revoked access, the authorization will still be good and Facebook will immediately redirect back to the app with a new authorization code to exchange for a fresh new access token. Therefore, whether the token has expired or not, the only way to get a fresh long-lived token after the initial long-lived token (as I understand it) is to go through the authorization flow again. So, one approach is for you to purposefully take the user through the authorization flow when they first come to your app on a given day and replace the existing connection with the new connection data. Or, you could wait until an ExpiredAuthorizationException is thrown and go through the process then. (Actually, it might be good to do this for any NotAuthorizedException.) At the moment, there's no support for either case in Spring Social. But here's how it might work (none of this is confirmed...just some sketchings I made):
These descriptions are purposefully brief so as not to get lost in the details of what should happen. I'm certain that gotchas will be encountered that I haven't thought of. One potential gotcha is dealing with the transactionality of the original request. Spring's transaction support should rollback anything that can be rolled back when a runtime exception is thrown, but what about non-transactional work that may have been done prior to the exception being thrown? Say, if a tweet was posted to Twitter and then an attempt to post to a person's Facebook wall is met with a NotAuthorizedException...how would that be handled? (Truth is, that's a problem right now and not only with Spring Social, but with any app that could perform non-transactional work before a transaction-killing exception is thrown.) |
The aforementioned filter/interceptor could also check for how much life is left on a token and if it falls under some configurable threshold go ahead and do the authorization flow as described above. (As an option to the once-per-visit-per-day approach.) |
I believe the problem that Facebook may be trying to solve is that when a Because of this new change a mobile application vendor who wishes to have
Of these, getting the token client side, passing it to the server, and In the following link
The access token has a ~1-2 hour access period
The token returned has a ~60 day expiration period On 5/11/12 1:24 PM, "Craig Walls"
|
Your explanation of how this impacts mobile makes sense, but I don't see how the same thing couldn't have been accomplished with a per-the-spec refresh token by keeping that refresh token server-side. Eventually the access token kept on the client will expire and the client will have to rely on the server-side to refresh the token. Conceptually, the endpoint Facebook is providing is no different than a refresh token endpoint would be except that you're using the not-yet-expired access token as the refresh token. Why not just implement the spec's refresh token and give guidance to mobile developers to handle the refresh on the server? And yes, I've performed those same steps you described probably hundreds of times while investigating this. My question remains: What happens when that 60-day token you obtained in step 4 starts growing stale? You no longer have a valid short-lived token to extend it any further and you can't extend a long-lived token. So you have no choice but to do the authorization again. |
I'm not arguing for/against the Facebook changes, I'm just trying to On 5/14/12 8:02 AM, "Craig Walls"
|
Completely understood. I did not mean to give the impression that I disagreed with your thoughts. I, too, am trying to get my head around this thing Facebook has done. That said, I will certainly consider adding the API call. But I do not plan to add it in such a way that it requires any changes to Spring Social Core just to support a Facebook-only quirk. I will seek out a solution that keeps the changes confined to Spring Social Facebook. |
I've the same need to extend a short lived access token, but I see this thread is old. Is there any "standard" method in spring-social-facebook to do it? |
I'm also looking for this feature, what is the latest news on this? |
Also looking for this or similar feature. Not sure if there is a better newer way to do this but it seems like I'm leaning towards @JohnWPhillips's
Also I'm not sure if there was a change to the FB api, but they don't advertise the OAuth2 method of grant_type='refresh_token' anymore. Calling the Facebook/Oauth2Template's refreshAccess function doesn't seem to work. Crafting the post manually doesn't seem to work either. To use the facebook extend api, I commandeered the existing refreshAccess function by:
Is there a better way to do this? |
@JohnWPhillips Please sign the Contributor License Agreement! Click here to manually synchronize the status of this Pull Request. See the FAQ for frequently asked questions. |
Facebook has begun supporting an OAuth2 extension to allow a server side request to exchange a short-lived Access Token for a Long-lived Access Token. I've added support for this into the spring-social OAuth2Operations interface and the spring-social-facebook FacebookOAuth2Template, please consider this for addition into a future spring-social release.
Since this is Facebook-specific an alternate implementation would be to subclass the OAuth2Operations interface in the spring-social-facebook package and have the user upcast the object from connectionFactory.getOAuthOperations(). This would be better because it would not add a Facebook specific API to the base class interface, however, it may be possible that what Facebook has done will somehow become part of a future OAuth standard and so it will need to be added to the base API at some point anyway.
Certainly interested in any insights SpringSource has into Facebook's deprecation of offline_access mode. Feel free to contact me at [email protected] for more info about my submitted changes.