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

fix: oauth redirect params legacy browsers support issue - OKTA-337243 #514

Conversation

shuowu
Copy link
Contributor

@shuowu shuowu commented Oct 19, 2020

Also need to cherry-pick this change to 3.2.x

@codecov-io
Copy link

codecov-io commented Oct 19, 2020

Codecov Report

Merging #514 into master will increase coverage by 0.22%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #514      +/-   ##
==========================================
+ Coverage   91.02%   91.25%   +0.22%     
==========================================
  Files          32       32              
  Lines        1839     1840       +1     
  Branches      407      409       +2     
==========================================
+ Hits         1674     1679       +5     
+ Misses        165      161       -4     
Impacted Files Coverage Δ
lib/token.ts 95.81% <100.00%> (+1.13%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 649f5bc...dbaffc5. Read the comment docs.

@shuowu shuowu changed the title fix: pkce redirect params legacy browsers support issue - OKTA-337243 fix: oauth redirect params legacy browsers support issue - OKTA-337243 Oct 19, 2020
lib/token.ts Outdated
}
// Add oauth_params to both cookies and sessionStorage for broader support
cookies.set(REDIRECT_OAUTH_PARAMS_NAME, tokenParamsStr, null, sdk.options.cookies);
browserStorage.getSessionStorage().setItem(REDIRECT_OAUTH_PARAMS_NAME, tokenParamsStr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we still need to check for session storage support (will it throw?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw the code in 3.x, I think it would be great to use the same logic in both version.

@aarongranick-okta
Copy link
Contributor

@shuowu Based on what we are seeing in this issue: okta/okta-oidc-js#898 Do you think it would make sense to use the same fallback logic for PKCE meta? Prefer session storage, but fall back to cookie if session storage is not available for some reason.

@shuowu
Copy link
Contributor Author

shuowu commented Oct 19, 2020

Do you think it would make sense to use the same fallback logic for PKCE meta? Prefer session storage, but fall back to cookie if session storage is not available for some reason.

Agree. We should write to all storages, then read the available value from there. Looks like the read order DO NOT really matter.

@aarongranick-okta
Copy link
Contributor

Looks like the read order DO NOT really matter.

It should not matter, but we did have the case where we had to favor cookie over session storage because the widget was writing to cookie but auth JS library was writing to session storage somewhere before the callback was handled (this was a concurrency issue if I recall correctly). Logically, we should favor session storage over cookie since only the cookie would be affected by cross-tab concurrency, but we may also want to favor whichever option is currently being used by SIW for maximum backward compatibility. If we are writing to both cookie and session storage, then any concurrency in the authJS library will overwrite whatever was set by the SIW. Unfortunately this is something we still have to deal with and we don't have a perfect solution yet.

@aarongranick-okta
Copy link
Contributor

aarongranick-okta commented Oct 19, 2020

The problem we had before was that we were only reading from session storage: https://github.com/okta/okta-auth-js/pull/491/files

Reading from the cookie first does help avoid a same-tab concurrency issue, but only because the SIW is only setting the cookie and authJS is only setting session storage. Once the SIW and authJS are setting both values, it should not matter, it will break on same-tab concurrency either way. and we should actually favor session storage to avoid cross-tab concurrency issue when a browser is reloading multiple tabs at the same time.

lib/token.ts Outdated
oauthParamsStr = browserStorage.getSessionStorage().getItem(REDIRECT_OAUTH_PARAMS_NAME);
}
if (!oauthParamsStr) {
// fallback to cookies to support legacy browsers, eg: IE/Edge, iphone 8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The iOS issue is actually the other way, the cookies will fail because of of sameSite logic which is incompatible with the logic in iOS 13

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the logic was

if (browserHasSessionStorage()) {
  // read from session storage
} else {
  // read from cookie
}

It was the else that caused the break. Session storage is enabled, but the value was in the cookie. We decided to favor cookie over session storage in that fix to also overcome same-tab concurrency (since authJS was only writing to sessionStorage), however multi-tab concurrency still exists.

With authJS writing to both values, there will be a potential single-tab concurrency issue, but we are fighting this in other ways. I do think it is correct to favor the value read from session storage first, to better defend against multi-tab concurrency.

let sdkMock;
let setCookieMock;
let sessionStorageSetItemMock;
let hasSessionStorage;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All local variables defined here should be reset in the beforeEach block. hasSessionStorage is not being cleared/reset in the beforeEach method, so the value from the previous test will remain unless it is set in the new test. This pattern can cause "flaky" tests since the behavior can vary based on what order the tests are run in, or if tests are run with other tests. But since this variable is a boolean it is difficult to reset.

In this case, I think it would be better to have a function like mockSessionStorage(enabled: boolean) which can be called by the test.

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

Successfully merging this pull request may close these issues.

4 participants