46

How do i make logins happen via Amazon Cognito REST APIs (for user pools) on platforms for which there is no official SDK? - Note that i am asking for user pools - not identity pools.


Synopsis


Amazon cognito provides 3 kinds of logins:

  • federated logins (creates identity pools) - using social connects like FB, Twitter, G+ etc
  • AWS managed logins (creates user pools) - using Amazon's own managed signup, signin, forgot password, reset password services
  • developer provided logins (my custom designed authentication service managed by myself)

I am using the second one (with User Pools)


Amazon cognito has several SDKs for android, iOS, javascript, Xamarin etc. Cognito also provides REST APIs for building on platforms other than those supported by official SDKs. I am building an app for a different platform and, hence, REST API is my only way as there is no official SDK for my platform.

The Cognito REST API provides various endpoints for 'sign up', 'forgot password', 'confirm verification' etc, but surprisingly, the REST API does not have any endpoint for simple signin / login.


From Cognito CLI API docs I have all the OFFICIAL CLI APIs necessary to "signup users", "confirm signups", "change passwords", "verify phone numbers", "forgot passwords" etc. Surprisingly there is no CLI API mentioned for LOGINs. I was hoping there should be some CLI API like "$ aws cognito-idp log-in" just like there is for "$ aws cognito-idp sign-up" or for "$ aws cognito-idp forgot-password" etc.


Also from this getting started tutorial it talks about "*what should be done with tokens received AFTER successful authentication of a user*". However, it doesn't talk about HOW TO make the successful authentication happen on the first place with Cognito User Pool APIs. Examples are available only for Android, iOS, javascript SDKs. There are no authentication examples available for platforms which do not have SDKs.


Hence, How do i make logins happen via Amazon Cognito REST APIs (for user pools) on platforms for which there is no official SDK?

Rakib
  • 12,376
  • 16
  • 77
  • 113

8 Answers8

89

This curl command works for me:

curl -X POST --data @aws-auth-data.json \
-H 'X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth' \
-H 'Content-Type: application/x-amz-json-1.1' \
https://cognito-idp.us-east-1.amazonaws.com/

Where aws-auth-data.json is:

{
   "AuthParameters" : {
      "USERNAME" : "yourusername@example.com",
      "PASSWORD" : "yourpassword"
   },
   "AuthFlow" : "USER_PASSWORD_AUTH",
   "ClientId" : "75........................"
}

The user pool client must allow USER_PASSWORD_AUTH for this to work - that's an AWS-side setting.

Yuri
  • 4,254
  • 1
  • 29
  • 46
andrewjj
  • 991
  • 1
  • 6
  • 3
  • 2
    Excellent answer, just note that if you are not using the us-east-1 region, you need to modify the url to add your region. – Alex Mantaut Jan 17 '19 at 01:27
  • 3
    Hi! Where can i find the cognito idp url? – Frank Feb 04 '19 at 10:46
  • @Frank just change the region in the url to whatever region you're using in the dashboard – Miguel Mota Feb 21 '19 at 03:09
  • 3
    This works great, thank you! Nowhere in the manuals can I find this, so kudos to you! :-) –  Apr 08 '19 at 13:38
  • @andrewjj I get 400 Bad Request { "__type": "NotAuthorizedException", "message": "Unable to verify secret hash for client 103------------------------------5" } – MSaudi Mar 26 '20 at 14:03
  • 2
    worked with me after creating another app client and disabled client secret credentials https://stackoverflow.com/questions/60869329/is-it-possible-to-login-to-amazon-cognito-via-rest-api-without-using-the-sdk/60870028#60870028 – MSaudi Mar 26 '20 at 14:54
  • 1
    Anyone? where are these documented in the AWS docs - X-Amz-Target, application/x-amz-json-1.1 ?? – human Jun 05 '20 at 13:54
  • The only place I've found this information (what is going on with that content-type header??) is observing the network traffic of the Amplify client. Nice work! I worry that it's not in the help docs, so might be prone to undocumented breaking changes in the future... – Squiggle Aug 12 '20 at 11:21
  • https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html – Ben Dec 17 '20 at 15:17
  • Is it possible to get the access token with the custom scope using the above endpoint? – tarkikshah Jun 09 '21 at 08:06
  • This works but also does not work. When you login with this method, you get the wrong scope. You get an admin user scope. When I try and use the access token returned I get a notice about an invalid scope. What do I need to do to do this to work with the correct scope? – David Parish Aug 16 '23 at 16:48
12

Update:

As you pointed out in the comments below, the authentication flow is documented here: http://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html. This might help to clarify the authentication flow

It is somewhat counter-intuitive, but it does make sense for mobile apps where you don't want to have the user explicitly sign in, but instead carry tokens around for the user. Note that there is an explicit signin (login) API in the AWS Userpools SDK for iOS. I have not used it, but I suppose it is just an alternate client side API to get through the same InitiateAuth() followed by a RespondToAuthChallenge() flow. The iOS signin example is documented here - IOS SDK Example: Sign in a User

Original Post:

The Cognito User Pools API documentation for initiating auth is available here

The way it works becomes clearer if you implement a user pools application in one of the SDK's (I did one in Swift for iOS, it is clarified because the logging of the JSON responses is verbose and you can kind of see what is going on if you look through the log).

But assuming I understand your question: In summary you should InitiateAuth() and the response to that (from the Cognito User Pools server) is a challenge. Then you do RespondToAuthChallenge() (also documented in that API doc) and the response to that is an authentication result - assuming that the password / session / token were accepted.

The combination of those two things is, I believe, what you are calling LOGIN, and it works like a login. In the API's, the way it is set up is that attempts to get user information when the user is unauthenticated kicks off that InitiateAuth() and (in iOS anyway) the API does a callback to the code you write to ask for passwords, and send a RespondToAuthChallenge() request etc.

Rakib
  • 12,376
  • 16
  • 77
  • 113
Bruce0
  • 2,718
  • 1
  • 17
  • 21
  • 7
    Nice.... I wonder why isn't there any straight forward example / instruction on how to sign in a user in the official docs. This flow was not quite intuitive. – Rakib Aug 20 '16 at 07:02
  • Yes, somewhat counterintuitive, but it does make sense for mobile apps where you don't what to have the user explicitly signing in, but instead carry tokens around for the user. Note that there is an explicit signin (login) API in the AWS Userpools IOS SDK. I have not used it, but I suspect it is just an alternate client side API to get at the same init-auth auth challenge sequence. Documented here. http://docs.aws.amazon.com/cognito/latest/developerguide/using-amazon-cognito-user-identity-pools-ios-sdk.html#using-amazon-cognito-user-identity-pools-ios-sdk-user-sign-in – Bruce0 Aug 20 '16 at 07:25
  • 1
    Yeah.... iOS, Android and JavaScript SDKs have good example and code samples. Other platforms don't have such rich examples. I am building on xamarin and unfortunately cognito docs for xamarin are not quite rich. Regardless, following your link, i was glad to find another sibling link which does talk about your challenge based authentication flow. http://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html Finally exactly what i was looking for. Thanks so much for responding. – Rakib Aug 20 '16 at 08:34
  • could you kindly edit your answer along with the official doc/guide links that we exchanged in the comments here? I would love to accept your answer with those details included in the answer. Please ping me here once you're done. – Rakib Aug 20 '16 at 08:44
9

Just to add to @andrewjj's answer. You might get back a challenge (NEW_PASSWORD_REQUIRED) as InitiateAuth response. It is when you are being asked to change passport on initial signin.

You can use Postman or curl command. This example expects Postman being used.

  1. InitiateAuth - This step is same as @andrewjj

Add this to Body as raw values

{
    "AuthParameters": {
        "USERNAME": "youremail@example.com",
        "PASSWORD": "temporary-password",
    },
    "AuthFlow": "USER_PASSWORD_AUTH",
    "ClientId": "2s........................"
}

Set headers

X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth
Content-Type: application/x-amz-json-1.1

Send a request to https://cognito-idp.us-east-1.amazonaws.com/ You might have to change region.

If you receive this response then your are ok, otherwise continue with step 2.

{
    "AuthenticationResult": {
        "AccessToken": "eyJra........",
        "ExpiresIn": 3600,
        "IdToken": "eyJra........",
        "RefreshToken": "eyJjd........",
        "TokenType": "Bearer"
    },
    "ChallengeParameters": {}
}
  1. RespondToAuthChallenge - this is new step

In case you receive Challenge back like this one:

{
    "ChallengeName": "NEW_PASSWORD_REQUIRED",
    "ChallengeParameters": {
        "USER_ID_FOR_SRP": "1231-......",
        "requiredAttributes": "[]",
        "userAttributes": "{\"email_verified\":\"true\",\"email\":\"youremail@example.com\"}"
    },
    "Session": "Sfas......"
}

You need to set new password. Add this to Body as raw values

{
    "ChallengeName": "NEW_PASSWORD_REQUIRED",
    "ChallengeResponses": {
        "USERNAME": "youremail@example.com",
        "NEW_PASSWORD": "newpassword"
    },
    "ClientId": "2s........................",
    "Session": "Sfas......(use one from the InitiateAuth response)"
}

Set headers

X-Amz-Target: AWSCognitoIdentityProviderService.RespondToAuthChallenge
Content-Type: application/x-amz-json-1.1

Send a request to https://cognito-idp.us-east-1.amazonaws.com/ You might have to change region.

Do step 1 again to receive tokens.

Black
  • 9,541
  • 3
  • 54
  • 54
  • Thanks. I was only after step 1 and it worked perfectly for me. Question though, where is the documentation for the header values you've mentioned? I checked https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html, but it does not mention these and neither is it mentioned under 'Common Parameters'. In fact, it does not even say what type of request it needs to be (POST in this case). – Ash Aug 20 '21 at 02:08
8

Sharing curl direct may help to anyone

curl -X POST --data @user-data.json \
-H 'X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth' \
-H 'Content-Type: application/x-amz-json-1.1' \
https://cognito-idp.<just-replace-region>.amazonaws.com/

file json user-data.json

{"AuthParameters" : {"USERNAME" : "sadfsf", "PASSWORD" : "password"}, "AuthFlow" : "USER_PASSWORD_AUTH", "ClientId" : "csdfhripnv7sq027kktf75"}

make sure your app client does not contain app-secret or create new app without secret. also inside app enable USER_PASSWORD_AUTH

Harsh Manvar
  • 27,020
  • 6
  • 48
  • 102
  • Thank you for this. I have no idea why on this earth AWS make this so difficult. If people are having to dive in to your SDK source code to figure out how to make an HTTP request to your services. Your docs suck. – Daniel Cooke Mar 16 '22 at 12:03
  • Definitely true, instead that should add the curl directly as an example so users can directly use it. – Harsh Manvar Mar 16 '22 at 12:06
6

One of the developers from AWS Cognito team here.

To add to @md-abdul-munim's answer, we recommend using one of the client side SDKs. If you are building a REST API and then a front end which talks to those APIs, it is better to just integrate Cognito from your front end.

If you absolutely need to use Cognito from a back end, the authentication APIs will be available with our GA release. In our Cognito User Pools beta release authentication is only available through client SDKs.

Community
  • 1
  • 1
Chetan Mehta
  • 5,491
  • 1
  • 22
  • 21
  • Can you elaborate further what you mean by GA release? – Rakib Jun 22 '16 at 04:27
  • In fact, we are using the Amazon cognito official Xamarin SDK for building a cross platform app with Xamarin. But even the official Cognito Xamarin SDK supports only signup, forgot password etc and it does not support logging in. – Rakib Jun 22 '16 at 04:42
  • By GA release I meant general availability. This is the time when the service comes of out of beta and should be within few months. – Chetan Mehta Jun 22 '16 at 05:28
  • ok... how about the Xamarin SDK? From here (http://docs.aws.amazon.com/mobile/sdkforxamarin/developerguide/cognito-identity.html) it seems like User Pools are still not part of the Xamarin SDK. – Rakib Jun 22 '16 at 08:21
  • I absolutely need to use Cognito from a Java back end. I don't have IAM access credentials, because the Identity Provider is managed by a vendor. There does not seem to be a good solution for this. – Jesse Barnum Apr 03 '20 at 17:38
  • Postman and similar tools don't have Amplify libraries, so unable to resolve an auth token as part of our automated API tests any other way. – Squiggle Aug 12 '20 at 11:24
1

From what you have discussed, I consider you are trying to do that from a web frontend. Cause, cognito is providing you the necessary backend support and it expects you to communicate(e.g. authenticate, sign up etc.) from a presentation layer- that's why you found SDK's for different mobile platforms. They also have SDK for web app- the access is available via their Javascript SDK.

Here's a detailed tutorial to achieve what you have asked from a web frontend using their JS SDK- Accessing Your User Pools using the Amazon Cognito Identity SDK for JavaScript

Munim
  • 2,626
  • 1
  • 19
  • 28
  • As i mentioned "*I am building an app for a platform for which there is no official Amazon Cognito SDK*". I am not building for web front-end. – Rakib Jun 22 '16 at 04:26
  • In that case, if you are trying to use cognito api for some sort of middleware you are developing(e.g. a python service)- I guess you are out of luck! :( – Munim Jun 23 '16 at 13:31
1

I have a similar problem and was wondering how to integrate Cognito within an Elixir backend and found this library: https://github.com/aws-beam/aws-elixir

From what I can understand by reading its source code, they ultimately make a POST request that contains the header "X-Amz-Target": "AWSCognitoIdentityProviderService.#{name_of_api_action}" (this is here: https://github.com/aws-beam/aws-elixir/blob/master/lib/aws/cognito_identity_provider.ex#L564). That's without the authorization headers, they are added elsewhere, but I found it interesting. The functions that construct the request URL are following, so you should be able to get an idea of the endpoint that gets called.

I must say I tried following this article written in Japanese - https://qiita.com/yujikawa/items/e79929ed14277102f4b8, and couldn't manage to make it work, maybe because I was not sure what the proper AWS_ENDPOINT environment variable should be. I am currently thinking of trying out the Ruby SDK, from the looks of the documentation it seems fine. But, nonetheless, this information may still help someone.

Nikolay D
  • 329
  • 3
  • 11
  • Wow. We have to restort to reading articles in Japanese - probably still easier to understand than the AWS documentation – Daniel Cooke Mar 16 '22 at 12:05
1

Thank @andrewjj, your answer is a big help.

Here is additional info for someone who has trouble with client secret. You don't need to turn it off.

You need to generate a secret hash from username, clientId, client secret, as following:

message = bytes(username+app_client_id,'utf-8')

key= bytes(clientSecret,'utf-8')

secret_hash = base64.b64encode(hmac.new(key, message, digestmod=hashlib.sha256).digest()).decode()

src: https://aws.amazon.com/premiumsupport/knowledge-center/cognito-unable-to-verify-secret-hash/

Then add the secret hash to your AuthParameters, as following:

{
   "AuthParameters" : {
      "USERNAME" : "...",
      "PASSWORD" : "...",
      "SECRET_HASH" : "..."
   },
   "AuthFlow" : "USER_PASSWORD_AUTH",
   "ClientId" : "..."
}
Tinchan
  • 41
  • 7