Sign AWS requests using Cognito Your User Pool user using Postman - amazon-web-services

I am trying to send an authenticated request to AWS API Gateway. The clients will authenticate against Cognito Your User Pools, and then obtain a token from an associated Cognito Identity Pool corresponding to the logged-in user in the user pool. I am trying to simulate such a request using Postman.
This post suggests that the command aws cognito-identity get-credentials-for-identity can be used to get the AccessKeyId and SecretKey needed for Postman to sign the request. However, when I try to run it with the sub attribute for a user from the Cognito User Pool console:
$ aws cognito-identity get-credentials-for-identity --identity-id aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
An error occurred (ValidationException) when calling the GetCredentialsForIdentity operation: 1 validation error detected: Value 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' at 'identityId' failed to satisfy constraint: Member must satisfy regular expression pattern: [\w-]+:[0-9a-f-]+
$ aws cognito-identity get-credentials-for-identity --identity-id us-east-1:aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
An error occurred (ResourceNotFoundException) when calling the GetCredentialsForIdentity operation: Identity 'us-east-1:aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' not found.
The same thing happens if I try to use an identity ID from the associated identity pool shown in the AWS Console (I selected one that has 2 "linked logins").

You need to pass along the login map :
--logins (map)
A set of optional name-value pairs that map provider names to
provider tokens.
Shorthand Syntax:
KeyName1=string,KeyName2=string
JSON Syntax:
{"string": "string"
...}
This syntax worked for me:
aws cognito-identity get-credentials-for-identity \
--identity-id us-east-1:aaaa-bbb-ccc-bc54-rrrrrrr \
--logins graph.facebook.com=kdajbdjkabkjbkjbkdbsckslcjxb
Note: --identity-id is not the identity pool id, its the identity from the identity browser.

API gateway now has native integration with 'Cognito Your User Pool', so you can pass the identity token directly - api gateway docs. The post you have linked is outdated

Related

Cognito user pool federated user unable to intiate-auth

Does AWS CLI cognito-idp initiate-auth support the USER_PASSWORD_AUTH flow for federated users from an external IdP (SAML provider)?
When I try to run initiate-auth, I am getting the below errors.
aws cognito-idp initiate-auth --region us-east-1 --auth-flow USER_PASSWORD_AUTH --client-id <my_client_id> --auth-parameters USERNAME=<username>,PASSWORD=<password>
An error occurred (NotAuthorizedException) when calling the InitiateAuth operation: User is not authorized to get auth details.
As a debugging step, I created a local user in the userpool, and using that I am able to get an AuthenticationResult back.
Also, the username and password work with a browser flow. (It redirects to my app url with the code) when triggered from the Launch Hosted UI link.
Am I missing something in the configuration?
Most likely, USER_PASSWORD_AUTH is disabled for federated users. The federated users have Confirmation status set to External Provider and these users can only login using the 3rd party identity provider.
The problem may be solved using Account linking.
Documentation: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-identity-federation-consolidate-users.html
I want to know if initiate-auth is supported for federated users but for CUSTOM_AUTHENTICATION. My research so far shows that this is not possible.

AWS STS Assume Role: Get session token

I am trying to get a session token for the given IAM in postman but not able to receive a token.
If I use boto3.client('sts'), I am able to get the token.
Use Case: I am trying to Invoke VPC Rest Endpoint from EC2 instance where ServiceNow mid-server instance is running. Since we have ServiceNow mid-server agent running on EC2 instance, I want to use IAM Role attached to EC2 to authenticate other VPC endpoints that are deployed in the same AWS account.
I have permission policy attached to IAM Role to allow Assume Role policy. If there any other approach, please suggest.
here HTML HTML response in postman. Postman redirecting to IAM Docs
client = boto3.client('sts')
response = client.assume_role(
RoleArn='arn:aws:iam::**************:role/ServiceNow-midserver-Role',
RoleSessionName='Session1',
DurationSeconds=3600
)
print(response)
anything wrong with postman request body or endpoint.
Authentication on postman is none.
To call AssumeRole from Postman (or curl etc.) as opposed to using a supported AWS SDK, you should follow the AssumeRole API documentation. You will also need to authenticate using AWS credentials.
Specifically, the request is an HTTP GET and parameters are passed as query strings, for example:
GET https://sts.amazonaws.com/
?Version=2011-06-15
&Action=AssumeRole
&RoleSessionName=stackoverflow-64706420
&RoleArn=arn:aws:iam::123456781234:role/myrole
&DurationSeconds=3600
Here's what this looks like in Postman:
And you will need to add AWS credentials so that your API request is signed correctly, for example:
Click 'Send' and the response will look something like this:
<AssumeRoleResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
<AssumeRoleResult>
<AssumedRoleUser>
<Arn>arn:aws:sts::123456781234:assumed-role/123456781234/stackoverflow-64706420</Arn>
<AssumedRoleId>ARO123EXAMPLE123:stackoverflow-64706420</AssumedRoleId>
</AssumedRoleUser>
<Credentials>
<AccessKeyId>ASIAIOSFODNN7EXAMPLE</AccessKeyId>
<SecretAccessKey>wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY</SecretAccessKey>
<SessionToken>
AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQW
LWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGd
QrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU
9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz
+scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==
</SessionToken>
<Expiration>2020-12-09T13:34:41Z</Expiration>
</Credentials>
<PackedPolicySize>6</PackedPolicySize>
</AssumeRoleResult>
<ResponseMetadata>
<RequestId>c6104cbe-af31-11e0-8154-cbc7ccf896c7</RequestId>
</ResponseMetadata>
</AssumeRoleResponse>
You need to use credentials for an IAM user or an IAM role to call AssumeRole. boto3 must be getting credentials from the standard locations it look for (like ~/.aws/config) [ref:https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html]. May be you could try providing the AWS creds in Authorization tab in Postman selecting type as AWS Signature and then call assumeRole.

AWS Cognito refreshing tokens against a different user pool also returns valid tokens

I was trying the AWS CLI for cognito.
I have a refresh token issued by user pool, let's say "A" with client ID "clientA".
I used this against a different user pool "B" in the same region. I specified client ID as "clientA" instead of B's own. This command worked and returned new access and ID tokens successfully.
$ aws cognito-idp admin-initiate-auth --user-pool-id "B"
--region eu-west-1 --client-id clientA --auth-flow
REFRESH_TOKEN_AUTH --auth-parameters "REFRESH_TOKEN=<refresh-token-from-A>"
It seems like AWS Cognito does not really use the "user-pool-id" parameter and only considers the client ID. Or otherwise this is a security loophole.
The documentation isn't massively clear about this, but the REFRESH_TOKEN flow does not use the client-id or user-pool-id as these are effectively provided by the Refresh Token itself. (Although the body won't validate without them...)
If you do some further commands on the CLI you'll see that the tokens you got back from that command only allow you to act as the originally issued client-id/user-pool-id.

Can't find refresh token when Cognito redirects back to my URL

I'm testing with AWS's Cognito. At this point, I can get back my IdToken, AccessToken, and RefreshToken like this:
$ aws cognito-idp admin-initiate-auth --user-pool-id us-east-1_XXXXXXXX --client-id XXXXXXXXXXXXXXXXXXXXXXX --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters USERNAME=XXXXXXXXXXXXX,PASSWORD=XXXXXXXXXXXXX --region us-east-1
Then I tried the default web page (provided by Cognito) at a URL like this:
https://test-cognito.auth.us-east-1.amazoncognito.com/login?response_type=token&client_id=XXXXXXXXXXXXXXXXXXXXXX&redirect_uri=https://example.com
This URL will take me to a page where I have to authenticate and once the process is done it will take me back to my redirect_url with previously mentioned IDs appended:
https://example.com#id_token=XXXXX.XXXXXX.XXXXXX&access_token=XXXXXX.XXXXXXX.XXXXXXX&expires_in=3600&token_type=Bearer
But there's no sign of refresh_token! How can I get my refresh_token in this scenario?
I don't think that is possible at present. AWS clearly states that refresh token is only available if the flow type is Authorization Code Grant.
What you are trying is Implicit Grant. The responseType is set to token in your case. For Authorization Code Grant, set the grant type to code but that will also need you to store the client secret in the app.
Source- https://developer.amazon.com/docs/login-with-amazon/refresh-token.html.
For more info on grant types - https://alexbilbie.com/guide-to-oauth-2-grants/

InvalidClientTokenId when using IAM user

I'm having trouble implementing GetCallerIdentity with AWS within my application. When I try to generate temporary credentials, the server console returns the error InvalidClientTokenId: The security token included in the request is invalid.
I've been looking at the AWS documentation and I'm wondering if I've set up my IAM user incorrectly. The documentation says;
The temporary security credentials created by GetSessionToken can be used to make API calls to any AWS service with the following exceptions:
You cannot call any IAM APIs unless MFA authentication information is
included in the request.
You cannot call any STS API except AssumeRole or GetCallerIdentity.
Does this mean I can't use IAM accounts with the below example? I'm building in meteor js and I'm trying to implement a package called SlingShot. The documentation doesn't mention errors like this.
var sts = new AWS.STS();
sts.getSessionToken({
DurationSeconds: duration
}, function (error, result) {
console.log('error', error);
callback(error, result && result.Credentials);
});