Skip to content Skip to sidebar Skip to footer

How Can I Check An Authenticated Resource Is Available Without Causing The Browser To Prompt For Credentials?

I'm trying to retrieve data from a web service on another server, but I don't know ahead of time if the user has an established session with that server. If they do, I'd like to a

Solution 1:

I have found one approach that seems to work for certain use cases. If the protected service happens to also have some way to send a valid image -- maybe they also protected a "login complete" page that has images on it, maybe they protected the Swagger docs page, doesn't matter -- then you can do an img tag test like this:

// Use a hidden `<img>` tag to test if the provided (protected) resource URL// can be loaded.  Resolves `true` if the image loads, or `false` if the image// fails to load.  Rejects if the provided timeout elapses before resolution.functiontestAuthWithImage(imgUrl: string, timeoutMS: number): Promise<boolean> {
    returnnewPromise((resolve, reject) => {
        const canary = document.createElement("img");

        functioncleanup() {
            window.clearTimeout(timeout);
            // Must remove event listeners so GC can clean up canary
            canary.removeEventListener("load", loaded);
            canary.removeEventListener("error", failed);
        }

        asyncfunctionloaded() {
            cleanup();
            resolve(true);
        }

        asyncfunctionfailed() {
            cleanup();
            resolve(false);
        }

        const timeout = window.setTimeout(() => {
            cleanup();
            reject("Connection timed out");
        }, timeoutMS);

        canary.addEventListener("load", loaded);
        canary.addEventListener("error", failed);

        // Assigning ths will cause the image to load or fail
        canary.src = imgUrl;
    });
}

As far as I can tell, it looks like all modern browsers will discard the 401 response without a login prompt when it's for a "subresource" in a different domain, as a means of phishing protection. Once I figured this out, handling customized login flow is easy:

protectedasynccheckLogin(promptForPass: boolean = false): Promise<UserIdentity | undefined> {
        if (awaittestAuthWithImage(this.TEST_IMG_ENDPOINT.url, this.timeoutMS)) {
            // The image-test worked so we have an existing session; just check the profile.try { returnawaitthis.fetchUserInfo(); }
            catch (err) {
                // If it was an HttpErrorResponse, throw the `message`throw err.message || err;
            }
        } elseif (promptForPass) {
            // If the test failed but we're prompting, show user/pass dialog immediatelyreturnawaitthis.doLogin();
        }
        // If we got here, we're not prompting so return undefined
    }

I think it should degrade gracefully in legacy browsers, because the subresource load (img tag) would cause a native login prompt, then fail or succeed based on what the user does with it. It won't work if the server doesn't already provide some suitable protected resource, though, and it does require at least one spurious request for the image in question, so I'd welcome a better answer.

Post a Comment for "How Can I Check An Authenticated Resource Is Available Without Causing The Browser To Prompt For Credentials?"