IdentityModel / oidc-client-js

OpenID Connect (OIDC) and OAuth2 protocol support for browser-based JavaScript applications
Apache License 2.0
2.43k stars 841 forks source link

localStorage and sessionStorage doesn't work for browsers in "private mode" #337

Closed stjepan closed 7 years ago

stjepan commented 7 years ago

Hi,

I see there are following user stores in the code: WebStorageStateStore and InMemoryWebStorage. When users are browsing in private mode, localStorage and sessionStorage are not accessable. InMemory is not usable since a reload would clear that one instantly as well.

What is your proposed workaround for that, so that I still can use your library?

Thanks in advance!

/Stjepan.

Sames as #269

brockallen commented 7 years ago

I don't have a solution for you. Is it just localStorage, or is sessionStorage also broken in these scenarios? I see why localStorage is blocked, but at least they could make it "go away" after the incognito window is closed. Seems like a very bad choice in the browsers.

GDehnke-Turpin commented 7 years ago

If you don't want to have it persist in the browser, as that is what it is sounding like, you could fallback to anysort of database of your liking... Else just change it to public mode...?!?!

stjepan commented 7 years ago

@brockallen localStorage and sessionStorage are basically the same, but in one case and that is sessionStorage clears out as soon as you close tab/browser. @GDehnke-Turpin The last options is cookies (in browser), which would work, but there is no official userStore in the solution. I know other fixed it that way, or by preserving it on the server, as you mention. https://github.com/IdentityModel/oidc-client-js/issues/269#issuecomment-303934113

brockallen commented 7 years ago

Yea, I'm fully aware. My point was that the incognito window could provide localStorage that was actually implemented similar to sessionStorage -- that would be better than it not working at all.

stjepan commented 7 years ago

I got it solved by implementing Secure Cookie Storage, if no other possible.

When in Private Mode, in Safari (both iOS and MacOS), localStorage and sessionStorage have length of 0, which will effectivelly throw an error as soon as you try to store anything.

MDN has a nice feature-detection function that can be used before you try writing to it. https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API

brockallen commented 7 years ago

Closing. If you still have issues, feel free to reopen.

stjepan commented 7 years ago

👍🏻 The current solutions of yours doesn't work when in private/incognito mode. My solution (with a help from another user) is by impl. secure cookie storage.

NateBrady23 commented 7 years ago

@stjepan would you mind pointing me in the direction of your solution?

stjepan commented 7 years ago

@nbrady-techempower Sure!

import Cookies from 'js-cookie';

const options = {
    secure: true
};

export default class CookieStorage {
    setItem = (key, value) => Cookies.set(key, value, options);

    getItem = key => Cookies.get(key, options);

    removeItem = key => Cookies.remove(key, options);

    key = index => {
        let allKeys = Object.keys(Cookies.getJSON());
        return index > -1 && index <= allKeys.length
            ? allKeys[index]
            : '';
    };

}
const storageAvailable = type => {
    try {
        var storage = window[type],
            x = '__storage_test__';
        storage.setItem(x, x);
        storage.removeItem(x);
        return true;
    }
    catch(e) {
        return e instanceof DOMException && (
            // everything except Firefox
            e.code === 22 ||
            // Firefox
            e.code === 1014 ||
            // test name field too, because code might not be present
            // everything except Firefox
            e.name === 'QuotaExceededError' ||
            // Firefox
            e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
            // acknowledge QuotaExceededError only if there's something already stored
            storage.length !== 0;
    }
}

export default storageAvailable;
import CookieStorage from './CookieStorage';
import storageAvailable from './storageAvailable';

export default class StorageFactory {

    static getStorage = () => storageAvailable('sessionStorage')
        ? sessionStorage
        : storageAvailable('localStorage')
            ? localStorage
            : new CookieStorage();

}
import { createUserManager } from 'redux-oidc';
import { WebStorageStateStore } from 'oidc-client';
import StorageFactory from './StorageFactory';

const userManagerConfig = {
    client_id: "your client id",
    redirect_uri: "your redirect uri",
    response_type: 'id_token',
    scope: 'openid',
    authority: "your authority",
    ui_locales: "your supported locales",
    userStore: new WebStorageStateStore({ store: StorageFactory.getStorage() }),
    stateStore: new WebStorageStateStore({ store: StorageFactory.getStorage() }),
};

const userManager = createUserManager(userManagerConfig);

export default userManager;

So, make sure you configure your userManager by overriding userStore and stateStore with the newly StorageFactory. It will check (with help of storageAvailable function, that I got from MDN) if client has support of session or local storage. If not, then it will fallback to the newly defined cookie storage.

Good luck!

brockallen commented 7 years ago

Relevant: https://twitter.com/rmondello/status/910276107978412034

primozs commented 6 years ago

Hello @stjepan, Is this still working for you? #631 I tried to change storage similar like you did, but I have an issue with userManager reading from cookie storage. Cheers

stjepan commented 6 years ago

Hi,

Unfortunately, I can’t confirm that. We have since then changed the way we’re doing this by tracking on the server side instead (through sessions). This is because of the limitation of storage when in private/incognito mode and/or older browsers that didn’t support either.

If you still wanna try using this, then download the project and see what interface you need to support and adjust the code accordingly.

Best luck!

/S.

On 3 Aug 2018, at 11:07, primozs notifications@github.com wrote:

Hello @stjepan, Is this still working for you? #631 I tried to change storage similar like you did, but I have an issue with userManager reading from cookie storage. Cheers

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

ghenadiibatalski commented 5 years ago

After clearing the storage in chrome -> all options checked -> clear site date, the local/session storage is working again also in incognito mode (at least in chrome 69 ).

stjepan commented 5 years ago

@ghenadiibatalski It is good to know your audience so that you can do a proper check on all browsers and devices. For us, this wasn't good enough, since we wanted to support ALL of our current customers (we did a rewrite and we didn't want our current customers to not being able to use the web page as before). And some of those were using elderly devices running Android that didn't played well with this.