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

Example on using state parameter to preserve query string #318

Open
rpwagner opened this issue Sep 28, 2024 · 3 comments
Open

Example on using state parameter to preserve query string #318

rpwagner opened this issue Sep 28, 2024 · 3 comments
Assignees
Labels
documentation Improvements or additions to documentation question Further information is requested

Comments

@rpwagner
Copy link

rpwagner commented Sep 28, 2024

What problem are you trying to solve?

When a page receives a set of query parameters like https://example.org/plot.html?file=a.csv I would like to know the appropriate way to persevere the query string file=a.csv after a login redirect. I believe this is typically handled via the state parameter in the OAuth flow, though I could be mistaken.

We are using this model to have a single page that view and interact with data from Globus Collections that require access tokens. This way, way can have a single viewer page and load different files based on the query parameters. Examples of doing this for public data are in our Cheap and FAIR template repo (see the view.md and chart.md pages).

Describe the solution you'd like

It would great to have an example like the basic login page that shows how to use the state parameter or other means to do this.

Describe alternatives you've considered

As a workaround, I will try collecting the parameters prior to creating the login manager and calling manager.handleCodeRedirect() or login().

@jbottigliero
Copy link
Member

jbottigliero commented Sep 30, 2024

@rpwagnerAuthorizationManager.login() and AuthorizationManager.handleCodeRedirect() will accept an optional options parameter. To pass query parameters through the OAuth handshake you can specify additionalParams.

manager.login({ additionalParams: { state: '...'  }});

But, taking a look a the internals here, I think you will encounter an Invalid State error when you call handleCodeRedirect – I can get that fixed.1

However, the state should be used to prevent cross-site request forgery (see https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1). If you don't provide a value, the SDK is creating a cryptographically strong random value that meets the OAuth spec requirements, if you provide your own you'll want to make sure you're doing some additional encoding rather than just supplying something like a.csv.

I can tell you in the applications we've been using the AuthorizationManager in, we've been managing application state outside of the OAuth handshake parameters (e.g. localStorage/sessionStorage values we reinstantiate post-handshake).

To do this, where you call manager.handleCodeRedirect you'll likely want to pass { shouldReplace: false }, process your storage then redirect on your own (e.g. window.location.replace).

Footnotes

  1. EDIT: This is addressed in fix(Authorization): ensure caller-provided "state" is stored on OAuth dispatch #319 and will be available in the next patch release.

jbottigliero added a commit that referenced this issue Sep 30, 2024
… dispatch (#319)

This will ensure the value in sessionStorage represents the
caller-provided value.

Relates to #318
@rpwagner
Copy link
Author

rpwagner commented Oct 1, 2024

Thanks @jbottigliero. Session storage was what I also considered.

Is this roughly what you're describing?

      UI.SIGN_IN.addEventListener('click', () => {
          /**
           * This will redirect the user to the Globus Auth login page.
           */
          let queryString = window.location.search;
          sessionStorage.setItem("queryString", queryString);
          manager.login();
          queryString = sessionStorage.getItem("queryString");
          window.location.search = queryString;
      });

@jbottigliero
Copy link
Member

Is this roughly what you're describing?

Rather than reading the value after .login() you would read that when the user is authorized (after the OAuth handshake).

Extending that basic example, I think you could do something like...

UI.SIGN_IN.addEventListener("click", () => {
  /**
   * This will redirect the user to the Globus Auth login page.
   */
  let queryString = window.location.search;
  // You'll set the value before you prompt for login.
  sessionStorage.setItem("queryString", queryString);
  // Since this will initiate the OAuth redirect, you can't really do any processing afterward.
  manager.login(); 
});

// ...

if (manager.authenticated) {
  const queryString = sessionStorage.getItem("queryString");
  if (queryString) {
     sessionStorage.removeItem("queryString");
     // do something;
  }

@jbottigliero jbottigliero added documentation Improvements or additions to documentation question Further information is requested and removed enhancement New feature or request labels Oct 3, 2024
@jbottigliero jbottigliero self-assigned this Oct 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants