Here is my scenario:
Have have a UserPool and an IdentityPool setup via Cognito. I also have an API-Gateway endpoint cofigured to authenticate with AWS_AIM.
First I log a user into the Cognito UserPool using their username and password. The response I receive is positive and looks like the following:
[AuthenticationResult] => Array
(
[AccessToken] => <AccessToken>
[ExpiresIn] => 3600
[TokenType] => Bearer
[RefreshToken] => <RefreshToken>
[IdToken] => <IdToken>
)
Using this information, I authorise the user with the Cognito IdentityPool. The response I receive is positive and looks like the following:
[IdentityId] => <IdentityId>
[Credentials] => Array
(
[AccessKeyId] => <AccessKeyId>
[SecretKey] => <SecretKey>
[SessionToken] => <SessionToken>
[Expiration] => Aws\Api\DateTimeResult Object
(
[date] => 2018-06-15 09:11:32.000000
[timezone_type] => 1
[timezone] => +00:00
)
)
And this is where I am stuck. I need the following headers in order to make the actual request to the API-Gateway Endpoint:
Authorization: AWS4-HMAC-SHA256
Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request,
SignedHeaders=host;range;x-amz-date,
Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024
But for the life of me I can't find a way to generate these headers. And the AWS SDK Documentation sets for Javascript and PHP is not particularly clear on what exactly to do. So my geuss is I missed a bit somewhere. Does any one have any knowledge on how to correctly generate these headers? Preferably using PHP.
I'm not well with PHP, but I know you need SignatureV4 signed request...isn't this what you are looking for?
https://github.com/aws/aws-sdk-php/blob/master/src/Signature/SignatureV4.php#L42
Related
Is there any way using AWS Cognito to send the user their verification code, have them enter the code, verify it is a valid code, THEN have them set their username and password?
For some reason, the workflow in my mind seems strange for the user to enter their code and new password in the same step. I want to check their code, and if it is valid, then take them to the screen to reset their password.
So far I've used the API function call:
forgotPassword
To send the code, which works fine, and from all my reading of the docs and searching here and online, I see that the next step is to call:
confirmForgotPassword
But in this step, it requires the new password (from what I can tell from the documentation):
$result = $client->confirmForgotPassword([
'AnalyticsMetadata' => [
'AnalyticsEndpointId' => '<string>',
],
'ClientId' => '<string>', // REQUIRED
'ClientMetadata' => ['<string>', ...],
'ConfirmationCode' => '<string>', // REQUIRED
'Password' => '<string>', // REQUIRED
'SecretHash' => '<string>',
'UserContextData' => [
'EncodedData' => '<string>',
],
'Username' => '<string>', // REQUIRED
]);
Am I missing something?
For context, I'm using the PHP API, but I'm really just looking for the correct API calls in the correct order to accomplish what I'd like if it is even possible.
Thanks in advance.
I changed my workflow so that I used a lambda function in AWS to send a link with the code, this way I validate the code on the link click and then the user can enter their password in.
Doesn't seem possible to do this in two steps.
Summary:
I tried to obtain AWS Cognito User name (OAuth2 from Google) with Perl module Paws::CognitoIdp::GetUser but I failed the code:
my $GetUserResponse = $cognito_idp->GetUser(
AccessToken => 'MyTokenModelType',
);
with the error Invalid Access Token.
Environment
I am developing Web service with following environment:
AWS + EC2 + Ubuntu 20.04 + nginx 1.20.1 + Perl 5.30.0
Using Cognito with Google OAuth2.0
What I can do now
When you access my Web service, Sign In with Google button will appear. If you click it, you can run my Perl CGI script.
What I cannot do now
I want to obtain your Google user name and mail address, but I cannot.
What I did
I wrote the following code:
my $cognito_idp = Paws->service('CognitoIdp',
region => "ap-northeast-1",
max_attempts => 3,
);
my $GetUserResponse = $cognito_idp->GetUser(
AccessToken => 'MyTokenModelType',
);
my $uname = $GetUserResponse->Username;
Then...
When I access my Web service, it failed with the Software error:
Software error:
Invalid Access Token
Trace begun at /usr/local/share/perl/5.30.0/Paws/Net/JsonResponse.pm line 22
Paws::Net::JsonResponse::process('Paws::Net::JsonResponse=HASH(0x56495fb33d78)', 'Paws::CognitoIdp::GetUser=HASH(0x56495fb41fd0)', 'Paws::Net::APIResponse=HASH(0x56495fde6f38)') called at /usr/local/share/perl/5.30.0/Paws/Net/Caller.pm line 46
Paws::Net::Caller::caller_to_response('Paws::Net::Caller=HASH(0x56495da09a38)', 'Paws::CognitoIdp=HASH(0x56495e05da48)', 'Paws::CognitoIdp::GetUser=HASH(0x56495fb41fd0)', 'Paws::Net::APIResponse=HASH(0x56495fde6f38)') called at /usr/local/share/perl/5.30.0/Paws/Net/RetryCallerRole.pm line 19
Paws::Net::RetryCallerRole::do_call('Paws::Net::Caller=HASH(0x56495da09a38)', 'Paws::CognitoIdp=HASH(0x56495e05da48)', 'Paws::CognitoIdp::GetUser=HASH(0x56495fb41fd0)') called at /usr/local/share/perl/5.30.0/Paws/CognitoIdp.pm line 331
Paws::CognitoIdp::GetUser('Paws::CognitoIdp=HASH(0x56495e05da48)', 'AccessToken', 'MyTokenModelType') called at /DocumentRoot/index.cgi line 16
For help, please send mail to this site's webmaster, giving this error message and the time and date of the error.
Maybe...
I referred following to the documentation
Maybe 'MyTokenModelType' is just the placeholder and I should specify the correct code.
But I don't know how I can make it.
In addition, I want to know how can I obtain not only user name but also user email address.
(Additional Info 2021-11-12)
Thanks to the comment, I read the article:
How to generate access token for an AWS Cognito user?
and I hacked AWS CLI command but I have not got the answer yet.
I think I got to do $ aws connito-idp initiate-auth but I cannot find what arguments I should pass.
In the AWS => Cognito => Users and groups menu, I see the entry of a user of my Web app.
Username: google_??????????
Enabled: Enabled
Account status: EXTERNAL_PROVIDER
Email: (users_email)
I changed my code like this for the experiment to find what information my Web app has.
use Data::Dumper;
my $cognito_idp = Paws->service('CognitoIdp',
region => "ap-northeast-1",
max_attempts => 3,
);
# my $GetUserResponse = $cognito_idp->GetUser(
# AccessToken => 'MyTokenModelType',
# );
# my $uname = $GetUserResponse->Username;
print "Content-type: text/html\n\n\n";
print '<!DOCTYPE html>';
print '<html><pre>';
print Dumper $cognito_idp;
print '</pre></html>';
and I see the contents of $cognito_idp like this:
$VAR1 = bless( {
'_region_for_signature' => 'ap-northeast-1',
...
'credentials' => bless( {
...
'selected_provider' => bless( {
'expiration' => 1636712506,
'actual_creds' => {
'Type' => 'AWS-HMAC',
'SecretAccessKey' => '??????????????',
'Code' => 'Success',
'AccessKeyId' => '???????????????',
'LastUpdated' => '2021-11-12T03:54:16Z',
'Token' => '?????????????????????????????????????',
'Expiration' => '2021-11-12T10:21:46Z'
},
...
I hope I could get the information of the user from the data above.
My question is, how I can specify the MyTokenModelType value of the code:
my $GetUserResponse = $cognito_idp->GetUser(
AccessToken => 'MyTokenModelType',
);
Still I want your info.
Thanks again.
I have an AWS Cognito User Pool where users are created through Cognito's API using the AdminCreateUser action, which works fine. This sends out a verification e-mail to the user, containing a temporary password. So far so good.
Now a user did not receive this verification e-mail, so I need to send it again, using the ResendConfirmationCode action. I am attempting to do that with the below PHP code.
$userPoolId = '[POOL_ID_HERE]';
$backendAppId = '[APP_ID_HERE]';
$clientSecret = '[SECRET_HERE]';
$username = '[UUID_HERE]';
$secretHash = base64_encode(hash_hmac('sha256', $username . $backendAppId, $clientSecret, true));
$cognitoIdp->resendConfirmationCode([
'ClientId' => $backendAppId,
'SecretHash' => $secretHash,
'Username' => $username,
]);
That gives me the following error:
Aws/CognitoIdentityProvider/Exception/CognitoIdentityProviderException
with message 'Error executing "ResendConfirmationCode" on
"https://cognito-idp.eu-central-1.amazonaws.com"; AWS HTTP error:
Client error: POST https://cognito-idp.eu-central-1.amazonaws.com
resulted in a 400 Bad Request response:
{"__type":"NotAuthorizedException","message":"Can't resend
confirmation code for this user"} NotAuthorizedException (client):
Can't resend confirmation code for this user -
{"__type":"NotAuthorizedException","message":"Can't resend
confirmation code for this user"}'
I am using the credentials of a user which has the following IAM permissions for the user pool:
cognito-idp:AdminDeleteUser
cognito-idp:AdminCreateUser
cognito-idp:AdminAddUserToGroup
cognito-idp:ResendConfirmationCode
If I test the permissions using the IAM Policy Simulator, it gives me the green light, saying that everything is OK. To my knowledge, the cognito-idp:ResendConfirmationCode action should be sufficient, as sending out the verification e-mail works fine when creating the user.
What am I doing wrong here? An alternative approach would be to invoke the AdminCreateUser action again, setting the MessageAction parameter to RESEND. This would force the verification e-mail to be resent for existing users, but I prefer using the ResendConfirmationCode action if I can get it to work.
Any ideas? Thanks!
I understand that you would like your web application end users to receive a confirmation code again if they do not get the confirmation code due to some reason after they sign-up, and I also understand that you are getting the "NotAuthorizedException" when you are trying to run the ResendConfirmationCode API call from your code that uses the PHP SDK.
The ResendConfirmationCode API call[1] can be used after the sign-up API call[2], and it is not a part of the AdminCreateUser Authentication flow, which is why the error is thrown. The AdminCreateUser API call changes the status of the new user to the "Force Change Password State", and neither the ResendConfirmationCode call or the ForgotPassword call can work after AdminCreateUser is used for creating a new user.
If you would like your end-users to get the confirmation code again, you could use the AdminCreateUser API call itself and set the "RESEND" flag in MessageAction in the PHP code. There would be no other way to send the verification message again in this particular use-case, as per my understanding of Amazon Cognito.
An example of the API call in PHP according to the official documentation is as follows[3]:
$result = $client->adminCreateUser([
'DesiredDeliveryMediums' => ['<string>', ...],
'ForceAliasCreation' => true || false,
'MessageAction' => 'RESEND|SUPPRESS',
'TemporaryPassword' => '<string>',
'UserAttributes' => [
[
'Name' => '<string>', // REQUIRED
'Value' => '<string>',
],
// ...
],
'UserPoolId' => '<string>', // REQUIRED
'Username' => '<string>', // REQUIRED
'ValidationData' => [
[
'Name' => '<string>', // REQUIRED
'Value' => '<string>',
],
// ...
],
]);
After using setting 'MessageAction' as 'RESEND', the end-users should be able to receive the verification message again on their end.
References
[1]. https://docs.aws.amazon.com/cli/latest/reference/cognito-idp/resend-confirmation-code.html
[2]. https://docs.aws.amazon.com/cli/latest/reference/cognito-idp/sign-up.html
[3]. https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-cognito-idp-2016-04-18.html#admincreateuser
I am trying to create ad account by following https://developers.facebook.com/docs/marketing-api/reference/ad-account. With the help of this code I could successfully create ad account but I want to add myself as people as well but not getting any way to do this.
My ad account creation parameters are like
$attachment = array(
'access_token' => $this->accessToken,
'name' => $associative_arr['name'],
'currency' => $associative_arr['currency'],
'timezone_id' => $associative_arr['timezone_id'],
'end_advertiser' => $this->businessAccount,
'media_agency' => 'NONE',
'partner' => 'NONE',
'user_role' => '1001'
);
and endpoint is
https://graph.facebook.com/v2.8/BUSINESS_ID/adaccount
I also tried updating ad account using following
https://developers.facebook.com/docs/marketing-api/aduser/v2.8
but no gain.
I am getting following error.
stdClass Object
(
[error] => stdClass Object
(
[message] => (#10) Application does not have permission for this action
[type] => OAuthException
[code] => 10
[fbtrace_id] => HyAJtY0OOMf
)
)
Can anyone give me suggestions how I can ad people to my ad account using curl or PHP SDK?
Besides getting the ads_management permission, what was your app's Marketing API access level? The default access level supports up to only 5 ad account access. If you've accessed more than that via the API, you won't be able to do that on more accounts unless you apply for higher level of access. You can manage your ad account list in your app dashboard.
I am using signed urls to upload files directly from the client straight into my S3 bucket. To do this I perform a direct put request to upload the file itself after having creating a signed URL of the command I want to perform.
I create the signed url like so:
$command = $s3->getCommand('PutObject', array(
'Bucket' => $this->_bucket,
'Key' => $key,
'ACL' => 'public-read',
'CacheControl' => 'max-age=0',
'ContentEncoding' => 'gzip',
'ContentType' => $filetype,
'Body' => '',
'ContentMD5' => false
));
$signedUrl = $command->createPresignedUrl('+6 hours');
However, after then performing the put request and uploading the file itself the Cache-Control and Content-Encoding headers are not set.
Does anyone have any idea where I am going wrong?
The headers still have to be set in the PUT request. Including them in the signed url isn't sufficient.
The pre-signed URL only serves to ensure that the actual request parameters match the authorized request parameters (otherwise the request fails).
So, if what I am saying is correct, then if these parameters aren't being sent with the request, it should fail, right? Almost.
Unfortunately, V2 authentication does not validate all request headers, such as Content-Encoding for example:
Note how only the Content-Type and Content-MD5 HTTP entity headers appear in the StringToSign. The other Content-* entity headers do not.
— http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html
The same is true for Cache-Control. Only x-amz-* headers are subject to validation against the signature provided in V2 (which uses &Signature= in the Query string).
V4 auth (which, by contrast, uses &X-Amz-Signature= in the query string) contains a mechanism allowing you to specify which headers need validation against the signature, but in either case, you have to send the headers with the actual request itself, not just include them in the signature. It appears that you aren't, and that's why they are not set.