2

I'm trying to implement the implicit grant OAuth flow using AWS Cognito. In particular, after having already logged in to my website, I'm trying to make a GET request to Cognito's AUTHORIZATION endpoint; the response from this request should redirect me to a URL of my choosing - let's call this the callback URL - and provide the desired access token in the fragment.

If I make this request by entering into the browser's address bar the appropriate URL for the AUTHORIZATION endpoint, everything happens as expected: The browser gets redirected to the callback URL, and the access token appears in the fragment of this URL.

However, if I make this same request asynchronously from a script in my website using XMLHttpRequest, I am unable to access the fragment returned in the callback URL (and Chrome's network tab shows that the token-containing fragment is in fact returned, just like in the address bar scenario described above). How can I access this fragment?

My code is as follows:

let xhr = new XMLHttpRequest();
let method = options.method.toUpperCase();

let extractFrom = ['url', 'code'];

xhr.open(options.method, options.url, true);
xhr.withCredentials = true;
for (const key in options.headers) {
    xhr.setRequestHeader(key, options.headers[key]);
}

xhr.onreadystatechange = function () {
    const status = this.status;
    const respUrl = this.responseURL;
    const respHeaders = this.getAllResponseHeaders();
    const respBody = this.response;

    if (this.readyState === XMLHttpRequest.DONE) {
        if (status === 200) {
            let val = extractParameter(extractFrom[0], respUrl, extractFrom[1]);
            resolve(val);
        } else {
            console.error('Other Response Text: ' + this.statusText);
            reject(this.statusText);
        }
    }
};

xhr.onerror = function () {
    console.error('Error: ' + xhr.statusText);
    reject(this.statusText);
};

xhr.send(null);
Tyler
  • 2,579
  • 2
  • 22
  • 32
  • When you say you cannot access the fragment, what do you mean? Are you getting any parameters, have you tried logging the whole URL? Is the problem that you don't have the URL when you expect to have it? – F_SO_K Apr 02 '19 at 07:55
  • On a side note, it doesn't seem like you need an async xhr.open call here. It's not like you are going to let the user do anything else whilst logging in, right? If you are struggling to get the params when you expect, you could try reconfiguring this so that the open async is set to false, then just check the response was a 200 and process it if so. – F_SO_K Apr 02 '19 at 08:00
  • For the server side implementation, the Authorization Code flow may be more advantageous: https://stackoverflow.com/questions/45785898/how-to-use-the-code-returned-from-cognito-to-get-aws-credentials We ended using it, letting Cognito return the `code` as query parameter, not `idtoken` as fragment, and then getting the full token from the code as described in that stackoverflow article. – geekQ Nov 08 '22 at 15:30

1 Answers1

2

The fragment is client site stuff, only stays in browser. You will need use javascript to pull it explicitly, see https://openid.net/specs/openid-connect-core-1_0.html#FragmentNotes. You could avoid fragment by using response_mode=form_post if OpenID Connect server supports it, see https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html.

Chunlong
  • 616
  • 5
  • 9