amazon-archives / amazon-cognito-auth-js

The Amazon Cognito Auth SDK for JavaScript simplifies adding sign-up, sign-in with user profile functionality to web apps.
Apache License 2.0
423 stars 232 forks source link

Authorization code grant flow not working #40

Closed megyfexid closed 6 years ago

megyfexid commented 6 years ago

If I turn off "Implicit grant" in my Cognito App client and leave only "Authorization code grant" then login fails and I get login#error_description=unauthorized_client&state=...&error=invalid_request.

If I turn on "Implicit grant" then the login works but I don't get a refresh token so I have to login every hour.

patvyas commented 6 years ago

By default, the SDK use implicit grant flow. To configure the code grant flow, you need to call useCodeGrantFlow on CognitoAuth So the code snippet looks like:

// Initialize a cognito auth object. function initCognitoSDK() { var authData = { ClientId : '', // Your client id here AppWebDomain : '', TokenScopesArray : '', RedirectUriSignIn : '', RedirectUriSignOut : '' }; var auth = new AWSCognito.CognitoIdentityServiceProvider.CognitoAuth(authData); auth.userhandler = { onSuccess: , onFailure: /* E.g. onSuccess: function(result) { alert("Sign in success"); showSignedIn(result); }, onFailure: function(err) { alert("Error!" + err); }/ }; // The default response_type is "token", uncomment the next line will make it be "code". auth.useCodeGrantFlow(); return auth; }

Then when getting the URL which contains all these three kinds of tokens, the SDK will extract the tokens and set their values accordingly. Please refer to this function: getCodeQueryParameter(httpRequestResponse) in CognitoAuth.js.

yuntuowang commented 6 years ago

By default, the SDK will use "implicit grant" flow. When you say "If I turn off "Implicit grant" in my Cognito App client and leave only "Authorization code grant" ", do you mean you put this setting on your user pool client setting on console? And if you want to enable "Authorization code grant", you need to check this option on console, also in your code, you need to uncomment this line: auth.useCodeGrantFlow(); Then the SDK can use code grant flow.

megyfexid commented 6 years ago

Thank you very much for the reponse.

I now call auth.useCodeGrantFlow()

Unfortunately this does not work in my case. The sdk just keeps getting code tokens in an endless loop.

I get a login callback url that looks like this: https://.../login?code=...&state=...

I then call parseCognitoWebResponse with the above url. Unfortunately parseCognitoWebResponse cannot parse this url.

parseCognitoWebResponse calls getCodeQueryParameter(httpRequestResponse) which calls getQueryParameters.

getQueryParameters fails to extract the code token from the url returns a map of: Map(1) {"undefined" => undefined}

Because getQueryParameters is unsuccessful in extracting the query parameters my next call to auth.getSession just starts the whole process over again.

It looks to me like your this.getCognitoConstants().QUERYPARAMETERREGEX1 is wrong. It's value is: /#(.+)/. This is why getQueryParameters fails to extract the code token.

This is wrong because as you can see in the callback url I posted above there is no # in the callback url from Cognito.

Am I doing something wrong? Should I not call parseCognitoWebResponse?

yuntuowang commented 6 years ago

Your calling parseCognitoWebResponse() is correct. Please refer to the CognitoAuth.js code carefully. Based on your login callback url that looks like this: https://.../login?code=...&state=...

parseCognitoWebResponse(httpRequestResponse) { if (httpRequestResponse.indexOf(this.getCognitoConstants().QUESTIONMARK) > -1) { this.getCodeQueryParameter(httpRequestResponse); } else if (httpRequestResponse.indexOf(this.getCognitoConstants().POUNDSIGN) > -1) { // To parse the response to get tokens this.getTokenQueryParameter(httpRequestResponse); } }

Because the callback url has "?", so in parseCognitoWebResponse(), it will call getCodeQueryParameter(),

getCodeQueryParameter(httpRequestResponse) { const map = this.getQueryParameters( httpRequestResponse, this.getCognitoConstants().QUESTIONMARK ); In which it uses question mark, not pound sign. It should parse the url correctly.

megyfexid commented 6 years ago

My getCodeQueryParameter does not look like yours. How do I get an update with the correct getCodeQueryParameter?

Mine looks like this: getCodeQueryParameter = function getCodeQueryParameter(httpRequestResponse) { var mapSecond = new Map(); mapSecond = this.getQueryParameters(httpRequestResponse, mapSecond); if (mapSecond.has(this.getCognitoConstants().CODE)) { // if the response contains code // To parse the response and get the code value. var codeParameter = this.getCodeParameter(httpRequestResponse); var url = this.getCognitoConstants().DOMAIN_SCHEME.concat(this.getCognitoConstants().COLONDOUBLESLASH, this.getAppWebDomain(), this.getCognitoConstants().SLASH, this.getCognitoConstants().DOMAIN_PATH_TOKEN); var header = this.getCognitoConstants().HEADER; var body = { grant_type: this.getCognitoConstants().AUTHORIZATIONCODE, client_id: this.getClientId(), redirect_uri: this.RedirectUriSignIn, code: codeParameter }; var boundOnSuccess = this.onSuccessExchangeForToken.bind(this); var boundOnFailure = this.onFailure.bind(this); this.makePOSTRequest(header, body, url, boundOnSuccess, boundOnFailure);

npm list says I am on amazon-cognito-auth-js@1.0.0. npm view amazon-cognito-auth-js version says the latest published version is 1.0.0.

How do I get your version? When will you publish it?

Looks like you have last published to npm in August 2017 but you did this fix in September 2017.

megyfexid commented 6 years ago

Ok installing directly from github fixed this issue for me. Your repository is outdated on npm.

I got stuck on this for 2 weeks and even aws developer support was not able to resolve this.

The 2 things that tripped me up:

  1. auth.useCodeGrantFlow() is not in your documentation I don't know how other people are getting this to work or maybe they are just logging in every hour.
  2. You haven't updated your package on npm.
yuntuowang commented 6 years ago

Glad that works! I am so sorry for the stuck. Thanks a lot for these two points, I just updated README.md to point out it. Will update my package on npm too. Thanks.