Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error "The state token is invalid or has expired. Please try again." when project is published to run anonymously #74

Closed
astillman opened this issue Aug 9, 2017 · 18 comments
Assignees

Comments

@astillman
Copy link

Unclear if this is is by design or not, but we're seeing "The state token is invalid or has expired. Please try again." when a project is published to run as the owner, and is accessible to anonymous users.

Any insights into whether this is the expected behavior for Apps Script in this context? Documentation doesn't suggest any requirements around publish state for the project.

As a workaround, we've been able to modify your code to use the published web app endpoint to handle the callback successfully. Any security concerns about using the doGet() endpoint of a public project to handle the callback?

@oshliaer
Copy link
Contributor

oshliaer commented Aug 9, 2017

@astillman , is there any example? It is very strange. I can't repeat the issue.

@erickoledadevrel
Copy link
Contributor

erickoledadevrel commented Aug 10, 2017

I believe this is due to how the /usercallback endpoint works. To quote myself from another issue:

"The library won't work for the scenario where the web app is deployed as the developer. This is because the state token forged when you get the Authorization URL has the developer's identity, but when the user hits the /usercallback URL is uses their identity."

This information was not added to the README however, and it should be there. Repurposing doGet() to handle the callbacks will work as intended, since that function will run as the developer.

Is anyone up for adding some info to the README, and perhaps adding a web app sample?

@astillman
Copy link
Author

@oshliaer to reproduce, publish a project with this library running in it as a web app, to "Execute the web app as Me (email address)" and be available to "Anyone, even anonymous." Per @erickoledadevrel the context in which the state token is generated is that of the developer, whereas the context of the state token's parsing is an "anonymous" context that apparently will not (likely by design) allow the state token to be parsed. This is likely because the concept of "state" here implies knowledge of user identity. When run in the anonymous context, there is nothing to link the callback to a specific user. In our use case, we accomplish this linkage via a custom parameter, but this is presumably a rare use case, and helps explain why the generic handling for this doesn't exist in native GAS methods.

@astillman
Copy link
Author

@erickoledadevrel we may be able to contribute, but can't promise quite yet given limited resourcing and the niche case this represents. Broadly, for the benefit of other travellers, so far we've added some prototype methods to the service to accommodate a custom redirect URL -- setting a configurable customRedirectUri property to be used within the chained service builder methods -- and modified the method to generate the callbackUrl to include custom params that allow us to identify the calling user. If there's demand from others for us to document further, please use this thread to make it known and we'll try to prioritize.

@mTorres
Copy link

mTorres commented Sep 27, 2017

@astillman, care to elaborate on how to acomplish this? You said that you've linked the token via a custom paramter. Which parameter? How did you code this configuration?

I'm in the same context as you and can't seem to work it out by myself.

@mTorres
Copy link

mTorres commented Sep 29, 2017

Ok, I had some time now and could work this out. I've used @erickoledadevrel tip and have set my callback to the public URL with a GET parameter. Then I've overwrote the handleCallback and getAuthorizationUrl methods in order to use the new RedirectUri. Then in the doGet() method I've just have to check if there is an oauth and a state parameters which means that this request is from an OAuth flow and from there call my callback function. It's quite ugly but it works. I'm not very skilled in JS, may be there is a way to override the getRedirectUri function from within client code? (I don't think so because it's a private function in the scope of this library, so if I'm overwriting it from my code, the library won't have a clue of it).

If there is no way to overwrite the redirect uri, may be the Service_ object could have some config option to allow the client code set this parameter easily?

@goelp
Copy link

goelp commented Mar 14, 2018

I was facing the same issue and upon trying a few things solved it by adding this code to generate the token:

function getStateToken(callbackFunction){
  var stateToken = ScriptApp.newStateToken()
     .withMethod(callbackFunction)
     .withTimeout(120)
     .createToken();
 return stateToken;
}

which needs to be called from the getService function like this:

function getService() {
  return OAuth2.createService('Quickbooks')
      .setAuthorizationBaseUrl(BASE_AUTH_URL)
      .setTokenUrl(TOKEN_URL)
      .setClientId(CLIENT_ID)
      .setClientSecret(CLIENT_SECRET)
      .setScope(API_SCOPE)
      .setCallbackFunction('authCallback')
      .setParam('response_type', RESPONSE_TYPE)
      .setParam('state', getStateToken('authCallback')) // function to generate the state token on the fly
      .setPropertyStore(PropertiesService.getUserProperties());
}

The whole code to make this work is available here:
https://gist.github.com/goelp/945ee0583e1df9663cc9e17ae5a2b9bb

@erickoledadevrel
Copy link
Contributor

@goelp I tried to get that solution to work, but it didn't seem to make a difference whether the Stake Token was created in the library or in the web app code. Have others seen success with that approach?

@erickoledadevrel
Copy link
Contributor

Closing due to inactivity.

@gupta-pratik
Copy link

Does anyone got the fix for this ? I had already implemented in the way @goelp has suggested. But this approach doesn't seems to be working.

@rodrigocava
Copy link

+1

I couldn't solve this as well

@denisakov
Copy link

+1
Just faced the issue, while the app isn't even published. Any definitive solution to this?

@jorgeforero
Copy link

I'm facing the same issue. Anyone with a possible solution?

@skrzymek
Copy link

skrzymek commented May 22, 2021

@erickoledadevrel +1
A solution is needed for the state token not to be related to the google account user running the app. I really want to have my web apps used by people without logging into my account :P

@lewis-cobry
Copy link

I've deployed my web app to execute as the user running it, but I'm still getting this error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

12 participants