SagePay Token issue - token

I am working for a client who has a legacy Server integration and make use of the Token system. The SagePay API shows they have 1583 saved Tokens however they only have 421 saved in their database - a huge discrepancy which I have been asked to investigate.
I think this is what has been happening:
Customer decides to click the "Save your card details" checkbox on their website
The POST is sent to SagePay containing "CreateToken=1&StoreToken=1"
Customer gets redirected to SagePay and decides to pay by PayPal instead
A Token gets created and the company gets charged for it even though it can't ever be used
The Dev before me only saved the Token from the notification page only if the payment type used was Credit Card which makes sense. What nobody realised until now was that SagePay would create and save Tokens even if the customer paid with PayPal [?] Surely this shouldn't be the case!
That means we have 1162 Tokens that we have simply lost control of. It is quite expensive to store so many Tokens and I have been asked to see if I can reduce the number. It is fairly easy to remove Tokens through the SagePay API, that is if you have the original Token! In this case, we don't have all of them.
I have contacted SagePay support but they just referred me to the API which doesn't solve the issue.
Will the Tokens we've lost control of simply naturally expire and delete?
Is there anything we can do to reduce the number of Tokens?
Thanks

There are two ways to create tokens:
As part of a PAYMENT, ask SagePay to additionally tokenize the card details (so you can reuse them without needing to store the card details)
Outwith a payment, you can send arbitrary card details and ask SagePay to store them in a TOKEN request.
If you are creating a token in a standalone TOKEN request, and then thereafter submitting a PAYMENT using the previously tokenized details, the solution I would recommend is creating a token as part of a PAYMENT (i.e one API request rather than two).
If you are already creating the token as part of the PAYMENT, the only solution I could recommend is keeping track of tokens stored in your data store, and if they haven't been used for any payments, have a scheduled job to remove these tokens (using the REMOVETOKEN request).

There seems to be a bug on submitting createToken=1 via Server, when the consumer selects Paypal - if you use the Reporting API to query such a useless token, the expiry returned is XXXX - which means it will never expire, so your client will be paying for it forever!
I'd contact Sage support if I were you and request a complete list of tokens that they hold, then use the API to query getTokenDetails on each, then discard those which are not usable / no longer active (via the REMOVETOKEN API call).

Related

Getting "invalid_grant" error when exchanging a refresh token for an access token

I've seen this issue in a lot of questions, but so far, none seem to apply to my situation.
The problem we are having is we are getting an "invalid_grant" error when we attempt to get an access token. This only happens to some accounts, but when it does happen, in every case I looked at, the refresh token worked before, and now has stopped working. This is happening far to frequently for it to be customers revoking access (seems to be nearly 20% of the channels we manage in the last couple weeks have been invalidated).
As a note, we have a backend process that uploads the videos to our customer's YouTube channels.
We use OAuth2 to get a refresh token, here are the parameters we send...
scope = "https://www.googleapis.com/auth/youtube",
client_id = "",
response_type = "code",
access_type = "offline",
approval_prompt = "force",
redirect_uri = "http://www.us.com/OAuth/YouTube"
NOTE: for client_id we use the email address that is in the Google API manager (or was, I just looked and it is no longer there). We used to use the client ID from this page, but that caused us problems as well. Did this change? Should we be using the client ID from this page now?
We exchange the code that is returned for a refresh and access token and store the refresh token in our database.
The backend process exchanges the refresh token for an access token and this is where we seem to be getting the "invalid_grant" error.
Guaranteed only a single access token for the channel is in use at any time (25 limit doesn't apply). We don't store the access token, we get a fresh one every time we process a channel.
Any ideas what might be happening? Something to look for? See note above about client ID. This might have something to do with it, but I'm hesitant to try it since using the "Client ID" from the API manager caused problems before.
Guaranteed only a single access token for the channel is in use at any time (25 limit doesn't apply). We don't store the access token, we get a fresh one every time we process a channel.
This statement is incorrect: Access tokens can be used as many times as you need while they are still good (for an hour).
Answer:
"invalid_grant" basically means that your refresh token no longer works. The only solution to the problem is to request access again and get a new one. The question should be why is it expiring in the first place.
Assuming that the user did not revoke access, and that the refresh token has been used to request a new access token within the last six months. This is probably an issue with it being over written.
When a user authenticates your application you are given a refresh token. This refresh token is associated to the client id of your application and the user who has just authenticated. If said user then authenticates your application again you will get another refresh token. Again this refresh token is associated to the user and your projects client id. Both of these refresh tokens will work. Your user can keep doing this up to 25 (Note I think the changed it recently to 50 but I haven't tested it with all APIs yet) once they have hit this magic number the first refresh token will expired and if you try and use it you will get an invalid grant.
The only solution is then to just request authentication again. It is important to always save the most recent refresh token that your user has granted your application. In the event (like me) you have an application that is stored on a number of servers all requiring authentication. Your going to have to tell them not to refresh it to many times or they will have to go back and reauthenticate the first one that they expired.
If this is happening with ALL of your requests. You can also check that you server is sync with (NTP) and that you are sending the payload of your request in the post field. Not attached to the authentication end point like a HTTP GET (been there done that).
Here are the possible reasons why a token stops working and becomes invalid:
The user has revoked access.
The token has not been used for six months.
The user changed passwords and the token contains Gmail scopes.
The user account has exceeded a certain number of token requests.
As you can see, it's not recommended that you request a fresh one every time you process a channel. As also mentioned in Token expiration:
If you need to authorize multiple programs, machines, or devices, one workaround is to limit the number of clients that you authorize per user account to 15 or 20. If you are a Google Apps admin, you can create additional admin users and use them to authorize some of the clients.
With regards to the use of client_ID, it is usually needed to call the sign-in API as mentioned in Creating a Google API Console project and client ID.
And lastly, this Google Groups discussion - OAuth 2.0 400 - error:invalid_grant and ideas? might also help.

How do you prevent session hopping using ASP.Net Web API?

Creating an angularjs single page application trying to use a RESTful API and I came across a problem that I can't seem to find an answer for. I was trying to prevent session hoping, one user logged in watching the requests figures out his account ID is 13. So he performs the same request but this time alters the request to get info for account ID 14.
So after the user logged in I was setting a session variable to his account ID and was going to strip the account ID out of the ajax requests. I then tried to access the Session from a class inheriting from ApiController. After looking around I realize that storing session information is not very RESTful.
So how would I go about ensuring that one account cannot access another account's information just because they watched the ajax requests and figured out how to manipulate the ajax request?
Is restful not meant to be used with users that need to authenticated and authorized? I was thinking of maybe hashing the IDs or something but I am not sure that is the right approach.
UPDATE:
I have token based authentication working now. But I am still in the dark as to how to prevent someone from fiddling with HTTP request and getting information that doesn't belong to him. For Example, I want to retrieve all the users for account with ID 14.
HTTP Get /users/14
I have a token so I know that the person trying to use the web API at some point authenticated themselves. I can lock it down to roles. But there is nothing stopping this authenticated person form fiddling/hacking with the request and doing the following
HTTP Get /users/58
Now the person has got all of account with ID 58's information. This is information does not belong to account 14 but now he can browse through other people's information.
I need someone of knowing that the request that comes from the browser and says it is for account with ID 14 that it really is account 14. I can put that information in the token but how do I check it in a handler or check it in the ApiController?
The problem you have described is not something unique to REST-based services. In fact, this is one of the top 10 OWASP vulnerabilities (Insecure Direct Object References). You will need to first identify the user and then authenticate the user. For identification, an ID is used, such as user ID. The identifier can be anything you want. After identification, you need to authenticate the user. This is done by authenticating the credential presented to the app, such as password. The identifier and the credential can be any thing, say the good old user name/password, or may be a token or may be an API key. It actually does not matter to the problem on hand. Once authenticated, you authorize the requests based on what the user can do in your app. The authz part is a must regardless of whether you use a token, certificate or what not. Hashing user ID or using some method to hide things is security by obscurity and is not a good practice.
Say, you are using a message handler to authenticate the credential submitted by a user. Once authentication is done you can store the account number associated with the authenticated user in the properties collection of HttpRequestMessage. This is done in the server side and no user can make the system store some random account number. Only the account number associated with the authenticated user is stored in the properties collection. With that, you can now authorize requests. Say, you can write an authorization filter that pulls this account number and compare it against the account number in the URI to determine if the request is allowed or not. By applying this filter against a GET action method, you can ensure only right folks can see right data.
For example, a user with user ID 'abc' and password 'pwd1' makes a GET request to /users/14. First step is, you will authenticate the user ID. If there is a user with ID 'abc' and password 'pwd1' in your store, you will consider the user authentic. As part of this authentication, you can pull the account number associated with the user 'abc'. Say it is 15. You will store 15 in request.properties. From your authorization filter, you can get the account number from URI, which is 14 and compare it against the one in the request, which is 15. Obviously the numbers do not match and you reject the request in the OnActionExecuting method of your filter with a 401.
What I described above is a simple approach. Better one (in terms of extensibility) will be to use claims but it will not be possible to explain all that here. You can get good amount of information related to claims-based identity from Dominick's blog.
Every request should be authenticated. If the credentials provided do not allow the user with account 13 to access data from account 14 then the request will be denied. The trick is to find a way to do authZ quickly.
You seem to be missing the information on how you want to implement authentication. As you correctly noted, using session to keep authentication information is not very restful. Here are the alternatives
Implement your own OAuth provider or use third party (for example
Azure ACS)
Implement STS provider (this is only for soap though)
Implement a custom token system, if you don't want to deal with
the above two. Basic system would take user id, salt it and encrypt with private key - but don't quote me on how secure that would be...
In all the cases, the authentication information is stored in the cookie, similar to session cookie. But it is still stateless.
The standard way on the web seems to be the oauth way, in fact the standard VS MVC template even comes with OAuth consumer implemented out of the box. So the question is, how do you link the oauth token to your internal user ID. That's really pretty simple, as you implement the "registration" step after the new user is authenticated - you keep user ID and oauth token in the database table, to link the two.
That link is quick to retrieve, and can be cached for speed. I have heard some people implement that type of credentials caching for some very big systems (google docs).

Using access tokens

I am trying to figure out how an access token in OAuth 2.0 should be used. To be more precise, I am trying to use the Google Plus API from a web application.
I am now able to get a code and from it an access token. The problem is that this token is only about 3600 seconds valid.
Is there a way to get another token without making the user go again through this process: https://developers.google.com/accounts/images/consent1.png because it seems a bit irritating. I know of the offline access and its refresh token, but it doesn't feel right to have permanent access to a user's account.
Do you have any ideas on how should I proceed?
I'm definitely not an authority, but I believe the answer is 'no'. The offline token allows you access without subsequent user approval, but only to the scopes to which the user already agreed when authenticating for the first time. Also, the user has the option of revoking your application's access at any time, which when combined with their previous consent means they both a.) know what they're allowing; and b.) can stop it at any time. Ostensibly, if a user uses your app enough that they constantly have to get a new token, they already trust it to act on their behalf within the scope you set, and the offline token is a way for you to take your relationship to the next level :)
I realize this is probably more philosophical than you were looking for, so apologies if it isn't pertinent to your situation.

offline_access deprecation and scenarios 3 and 4

Every time I read https://developers.facebook.com/roadmap/offline-access-removal/, I'm left more confused than the time before. I'm looking for some clarification on some items under scenarios 3 and 4 (server-side apps and client-side apps)
For server-side apps, it states "If the call is made while there is still a valid 60-day access_token for that user, the returned access_token from this second call may be the same or may have changed, but in either case the expiration time will be a fresh 60 days."
What is "the call" that is referred to here?
Is it the same exchange of an authorization code for the access token that takes place during the initial OAuth flow?
Or is it the endpoint call described under the client-side section to freshen the token to 60 days?
If it's the former, then where does the authorization code come from when trying to renew the token?
Is it the same authorization code from the original callback or do I have to go through the authorization flow again?
In short, can a server-side app keep freshening the life of a 60-day token and, if so then how?
Regarding client-side use, the document indicates that the client must make that endpoint call passing in (among other things) the application's client ID and client secret.
My interpretation of "client-side" may be wrong, but I'm thinking in terms of a JavaScript-based client running in a web-browser.
If that's what Facebook has in mind here, then should the JavaScript code really ever know about the client secret? (It won't be much of a secret if it's sent to the client.)
Even then, it indicates that 60-day tokens cannot have their life extended and that a new 2-hour token must first be acquired and used to get a 60-day token. This is under the client-side portion of the document, but does this rule apply to server-side 60-day tokens, too? If not, then I ask again: How do I freshen the life of a 60-day token on the server-side?
Finally, the question that has been burning in my mind for some time: Why has Facebook adopted this strategy and not adopted the refresh token as defined in the OAuth 2 specification (a specification that Facebook is helping define)???
EDIT: Further thoughts/questions after re-reading the document again:
At the beginning it says "a long-lived expiration time that can be renewed each time the user revists your app". My initial assumption is that the way to renew it would be to make a call to the endpoint later in the document. But, aside from the fact that the endpoint is described under the "client-side" heading, it also states "Please note, the endpoint can only be used to extend the short-lived user access_tokens. If you pass an access_token that had a long-lieved expiration time, the endpoint will simply pass that same access_token back to you without altering or extending the expiration time." (The typo on "long-lieved" is from FB's own documentation.)
Okay, so if that endpoint cannot be used to renew the expiration time (and my own attempts to renew a long-lived token with that endpoint prove this out), then how can I renew the expiration time on a long-lived token each time they visit my app?
Is there no one who understands how this is supposed to work?
After reading Facebook's doc (like for the 5th time) and with the help of this question/answer this are my conclusions.
What is "the call" that is referred to here?
It referres to the OAuth call to get an access token.
Is it the same exchange of an authorization code for the access token
that takes place during the initial OAuth flow?
Yes, I believe it's that flow.
Or is it the endpoint call described under the client-side section to
freshen the token to 60 days?
No, that endpoint is only valid for short-lived access tokens.
Is it the same authorization code from the original callback or do I
have to go through the authorization flow again?
You've to go through the authorization flow again.
how can I renew the expiration time on a long-lived token each time
they visit my app?
Long-lived access tokens cannot be renewed using the client side endpoint. The user will have to reauthorize the app to get a new one.
According to Facebook documentation:
If the call (OAuth authorization call) is made while there is still a valid long-lived user
access_token for that user, the returned user access_token from this
second call may be the same or may have changed, but in either case
the expiration time will be set to a long expiration time.
Once the application is reauthorized you'll get a new expiration time. Facebook may return a new long-lived access token, so you should grab it and replace that information for the one you already had.
Conclusion:
Seems there's no way to renew a long-lived access token without user intervention. To get a new expiration time/access token they'll have to reauthorize your app. My humble advice is that should suggest the user to reauthorize it, a few days before the expiration date.
Also, this Facebook how-to can came in handy for checking expired access tokens.

How to handle Facebook's deprecation of offline_access when you use token both in both iOS app and a server

Facebook's deprecation of the offline_access permission is coming May 2012 and the documentation isn't giving us enough information on how to handle it.
We have an iOS app and corresponding service that powers it and integrates with Facebook in a deep way to leverage a user's friend list within out app (so if your FB friends are also using the app you can more easily connect). This is like how all social apps seem to work, so nothing special here.
Client
Our app uses Facebook iOS SDK to allow user to login, which we currently ask for offline_access. The token is persisted in our iOS app, but also sent to our server where it is saved. The client acts on behalf of user to post updates to a user's newsfeed (we also ask for publish_stream permission).
Server
Our server periodically checks to see if user's FB friends are now using our app. Next time user signs in, we expose content and relationships in a certain way to promote that user's friends. The server also acts on behalf of the user to periodically connect to the graph API and get the user's current friends list. This is so we can account for changes in a user's relationships and have them reflected in our app. We do this when the user isn't currently using the app so they have the best experience the next time they do use it. To enable this, our iOS app sends the access token to our server which it uses and why we ask for offline_access.
Note: If user signs out of our app explicitly, we delete the access tokens from both client and server.
Problems
Now that there is no longer a perpetual access token we can use, I'm trying to figure out the best practice for still enabling our scenarios while leveraging facebook's new intended way of handling and extending access tokens. The documentation is unfortunately not totally helpful.
Questions
A. When you authenticate through the newest Facebook iOS SDK, what is the default lifetime of the access token you get? This document says an extended token request will give you one that lasts 60 days. This other document talks about the first access token request and mentions varying validities but it's unclear and does it talk about specific validity times:
(emphasis is mine)
When you obtain an access token from Facebook, it will be valid
immediately and usable in requests to the API for some time period
defined by Facebook. After that period has elapsed, the access token
is considered to have expired and the user will need to be
authenticated again in order for your app to obtain a fresh access
token. The duration for which a given access token is valid depends on
how it was generated.
There are also events which may cause an access token to become
invalid before its expected expiry time. Such events include the user
changing their password, an application refreshing it's App Secret.
Dealing with varying access token expiry times, and handling the case
when an access token becomes invalid before its expected expiry time
is essential for building robust social experiences.
B. For the client, now that the access token isn't necessarily long lived, is the right approach for us to:
Let use login through FB, then detect whenever the access token is expired. If it is, then call into FB iOS SDK to re-authentication/re-authorize? (this should just trigger user to bounce out to FB iOS app, and in most cases come immediately back to our app with a new access token).
C. According to this blog post I found, you can only extend an access token once:
Can I exchange my 60 day access token for a new 60 day access token?
No, sorry you cannot. You can only exchange a valid (meaning current)
user access token for an extended one. You cannot extend an already
extended access token.
On the client, I can just handle this by prompting a re-authentication/re-authorization as I mentioned in Question B. However, this doesn't work on our server. We could certainly have the server renew it once to 60 days, but what happens on the 61st day? The server just stops being able to sync the friend's list?
D. It seems to make sense to check the validity of the FB access token every time the app starts or re-hydrates from sleep. What is the best way for our iOS app to check this? Is there a recommended endpoint to call to validate a token? Should we just call into https://graph.facebook.com/me passing the access token and checking the response?
Note: we can certainly record the expires time when we get the initially extended token, but this isn't reliable since the user could revoke our app's permission anytime which makes the expires time an unreliable data point on validity
Overview
I believe that the root of what facebook is trying to achieve is to prevent an app from having perpetual ever-lasting access to a user's account. So, with the new migration an app can only access an account for 60 days unless the user signs in again.
I don't work for facebook, but here are my findings from playing around with the facebook graph api.
General Solution
Whenever a user signs in, take their access token and immediately extend/refresh it, and save it
Record the expiration date of the access token
When an access token expires (either from the recorded date, or a graph API exception telling you so), then notify the user that you don't have access, and ask them to sign in again.
Answers
A. When you authenticate through the newest Facebook iOS SDK, what is the default lifetime of the access token you get? This document says an extended token request will give you one that lasts 60 days. This other document talks about the first access token request and mentions varying validities but it's unclear and does it talk about specific validity times:
Here's how it works:
The first sign-in grants you approximately two hours
By refreshing the access token, you can get up to 60 days
If the user doesn't sign in to those 60 days, there is no way to get access for longer without having them sign in.
If the user de-authorizes your app, that 60 day windows ends immediately, and you will no longer have access.
B. For the client, now that the access token isn't necessarily long lived, is the right approach for us to: Let use login through FB, then detect whenever the access token is expired. If it is, then call into FB iOS SDK to re-authentication/re-authorize? (this should just trigger user to bounce out to FB iOS app, and in most cases come immediately back to our app with a new access token).
If the users access token is expired, your only option is to have them go through a login loop like you are talking about.
C. According to this blog post I found, you can only extend an access token once. On the client, I can just handle this by prompting a re-authentication/re-authorization as I mentioned in Question B. However, this doesn't work on our server. We could certainly have the server renew it once to 60 days, but what happens on the 61st day? The server just stops being able to sync the friend's list?
You can only extend an access token once. On the 61st day, you are out of luck. Best notify the user and let them know that unless they sign in, you won't be able to do anything.
D. It seems to make sense to check the validity of the FB access token every time the app starts or re-hydrates from sleep. What is the best way for our iOS app to check this? Is there a recommended endpoint to call to validate a token? Should we just call into https://graph.facebook.com/me passing the access token and checking the response?
I haven't be able to find an API equivalent of the Debug Console. This FB blog article talks about invalidated access tokens, but doesn't mention any API methods in particular meant to test the API.
I your suggestion of hitting https://graph.facebook.com/me would work just fine is exactly what they recommend in their example. In fact, I might use this approach in my app as a pro-active way of checking an access token.
Tid Bits
When you "refresh" an access token, a new access token will be returned. The response looks like: access_token=TOKEN&expires=5183912
You can only "refresh" an access token once. If you try to "refresh" the long-lived token returned from a previous call, it will return the same token, but doesn't throw an exception unless the token has expired. (in other words, you can safely try to refresh your token)
The default access token length seems to be around 2 hours
If you "refresh" an access token, that new access tokens seems to be the one that you'll get from the facebook API afterwards (instead of returning the original, short-lived access token)
Also, if you want to play around, these tools make it easy to test out your use case in a browser before burying it in your code:
Graph API Explorer - For creating and getting access tokens
Debug Console - For checking the expiry date of tokens before/after refresh
Refresh Endpoint - For manually testing extending your tokens
Great answer, one important addition : the default token lasts between 1 and 2 hours. You get the remaining of the hour during which the user signs up, plus 1 full hour. For example if a user signs up at 3:45pm, the access token will expire at 5pm. To be safe developers should assume it only lasts 1hour.

Resources