Custom Authorization
Lambda Execution Role : Full Access Api Gateway and Lambda
Token Source: method.request.header.Authorization
Token Validation: blank
Add this custom authorization to api method request . Authorizers test is succes but ı request to api on Postman then 401.
{
"message": "Unauthorized"
}
Custom Authorizer Lambda
console.log('Loading function');
exports.handler = function(event, context, callback) {
console.log("event:",JSON.stringify(event)); console.log("event:",JSON.stringify(context));
console.log('Client token: ' + event.authorizationToken);
console.log('Method ARN: ' + event.methodArn);
callback(null, {
"principalId": "18",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1459758003000",
"Effect": "Allow",
"Action": [
"execute-api:Invoke"
],
"Resource": [
"arn:aws:execute-api:*"
]
}
]
}
});
}
Postman Code:
curl --request GET \
--url {url} \
--header 'authorization: Test Token' \
--header 'cache-control: no-cache' \
--header 'content-type: application/json' \
--header 'postman-token: c9110a92-414e-e1aa-61fb-194758dace86'
Solution
Token Source: Authorization
API Gateway has changed, as of today Jan 18. Following needs to be know.
If the Method's Integration Request is not lambda proxied. While creating custom authorier (in Authorizer tab) , you should enter Token Source as "Authorization" and not "method.request.header.Authorization". Also , in the Method Request tab of the method ( eg GET) , you should set the HTTP Header Mapping , for 'Authorization'.
If the Method's Integration Request is proxied , no mapping is required. All the request body+header+parameter+AWSextraStuff is avaliable in the event[] object of lambda. Hence no mapping is required.
Few more pitfall be careful.
- Use standard string like 'Authorization' ( which is a standard) , is you use different string , change every where.
- The authorization token when passed to lambda, for no proxied integration request, as event['authorizationToken']and not event['Authorization']
- If you get error like Lambda Malform... , it is because you are using Lambda Proxy and it requires response in specific format, your not sending data in tha format.
- If your using Postman , switch to 'raw' against 'pretty' mode.
To call an API with the custom TOKEN authorizer
Open Postman, choose the GET method and paste the API's Invoke URL into the adjacent URL field.
Add the custom authorization token header and set the value to allow. Choose Send.
Worth read - http://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html#call-api-with-api-gateway-custom-authorization
You don't call the Custom Authorizer through Postman, that's API Gateways' job.
Every time that you call an endpoint protected by your custom authorizer the API Gateway will check if the value of the given Authorization Header exists in its Policies Cache. If the value does not exist, your Custom Authorizer will be called to authenticate the request.
A simple representation of the flow:
Lambda Handler (handles a protected endpoint GET /users/{id})
|
| ------------
| |
| Custom Authorizer
| /
| / (if the request is not authorized yet)
| /
Api Gateway
|
|
|
Request (with Authorization Header)
You just have to set the Authorization of your resource method to your custom authorizer and let the API Gateway do all the work.
Related
I'm attempting to call Google Cloud's signJwt method with Workload Identity Federation with a service account via domain wide delegation. As far as I can tell I'm following Google's instructions exactly but am getting the following error:
{
"error": {
"code": 400,
"message": "Request contains an invalid argument.",
"status": "INVALID_ARGUMENT"
}
}
I'm running the following curl command in the Cloud Shell
curl -X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json; charset=utf-8" \
-d #request.json \
"https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/<SA_USERNAME>%40<PROJECT_NAME>.iam.gserviceaccount.com:signJwt"
where request.json contains the following:
{
"payload": "{\"iss\":\"<SA_USERNAME>#<PROJECT_NAME>.iam.gserviceaccount.com\",\"scope\":\"https://www.googleapis.com/auth/gmail.readonly\",\"aud\":\"https://oauth2.googleapis.com/token\",\"exp\":1672868057013,\"iat\":1672868053513,\"sub\":\"<USER_NAME_OF_USER_TO_IMPERSONATE>#<DOMAIN>\"}",
"delegates": [],
}
Why am I getting an invalid argument error?
Try something like this in the request body :
{
"delegates": [
string
],
"payload": string
}
As given in the document:
The sequence of service accounts in a delegation chain. Each service
account must be granted the roles/iam.serviceAccountTokenCreator role
on its next service account in the chain. The last service account in
the chain must be granted the roles/iam.serviceAccountTokenCreator
role on the service account that is specified in the name field of the
request.
The delegates must have the following format: projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}. The - wildcard character is required; replacing it with a project ID is invalid.
Also there is a bug request on it.You can raise a new request if you need it by using the issue tracker.
I am trying to use AWS API Gateway as a reverse (forwarding) proxy to AWS SQS using the configuration as seen in the screenshots. I essentially want to send a REST request to the API Gateway which then gets forwarded directly to the SQS REST API and returns the response.
When I send a request to the gateway, I immediately get back
<?xml version="1.0"?>
<ErrorResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
<Error>
<Type>Sender</Type>
<Code>AccessDenied</Code>
<Message>Access to the resource https://sqs.us-east-1.amazonaws.com/ is denied.</Message>
<Detail/>
</Error>
<RequestId>51c903b2-4da3-5d5e-a3b8-589ee72167de</RequestId>
</ErrorResponse>
However, when I switch the request URL to SQS directly (https://sqs.us-east-1.amazonaws.com) the request succeeds.
What am I missing?
curl --request POST 'https://my-api-gateway.com/sqs' \
--header 'X-Amz-Date: <date>' \
--header 'X-Amz-Security-Token: <token>' \
--header 'Authorization: <auth>' \
--header 'Amz-Sdk-Invocation-Id: <invocation>' \
--header 'Amz-Sdk-Request: attempt=1; max=10' \
--header 'User-Agent: aws-sdk-go-v2/1.16.5 os/macos lang/go/1.18.3 md/GOOS/darwin md/GOARCH/arm64 api/sqs/1.18.6' \
--header 'Content-Length: 206' \
--data-urlencode 'Action=ReceiveMessage' \
--data-urlencode 'MaxNumberOfMessages=10' \
--data-urlencode 'QueueUrl=<my-queue-url>' \
--data-urlencode 'Version=2012-11-05' \
--data-urlencode 'WaitTimeSeconds=20'
The API gateway integration needs to have an invocation role attached to it. This IAM role must have SendMessage policy for your SQS, so that your API gateway integration has access to push data to your queue.
For this, first create an IAM role with this policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "sqs:SendMessage",
"Resource": "arn:aws:sqs:eu-west-1:1234:your-queue-name"
}
]
}
Now go to API Gateway > Manage Integrations > Select your integration > Edit > Add the ARN of the newly created IAM role in Invocation role field
like this
I have created a API Gateway and I have applied Cognito Authentication there. Here to have the API Call work I am using AWS CLI to get Token , Here is my CLI Code
aws cognito-idp admin-initiate-auth --user-pool-id us-west-2_leb660O8L --client-id 1uk3tddpmp6olkpgo32q5sd665 --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters USERNAME=myusername,PASSWORD=mypassword
Now I want to use CURL Call instead of this CLI Call. I have found the code but all needs client secret here. I do not have client secret as my user pool is of Enable Signin for server-based authentication.
Please guide me how I can use that.
I have gone through
https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html
[What will be the EndPoint for Calling IntiateAuth Or AdminIntiateAuth]
&
https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html
To Summarise this :
I want to get Id_Token Using Curl or Postman without Client Secret.
Thanks in advance
You can authenticate a user with the following request.
This is the endpoint of the InitiateAuth request.
Hope that this is useful for you
Method: POST
Endpoint: https://cognito-idp.{REGION}.amazonaws.com/
Content-Type: application/x-amz-json-1.1
X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth
Body:
{
"AuthParameters" : {
"USERNAME" : "YOUR_USERNAME",
"PASSWORD" : "YOUR_PASSWORD"
},
"AuthFlow" : "USER_PASSWORD_AUTH", // Don't have to change this if you are using password auth
"ClientId" : "APP_CLIENT_ID"
}
And the response as the following
{
"AuthenticationResult": {
"AccessToken": "YOUR_ACCESS_TOKEN",
"ExpiresIn": 3600,
"IdToken": "YOUR_ID_TOKEN",
"RefreshToken": "YOUR_REFRESH_TOKEN",
"TokenType": "Bearer"
},
"ChallengeParameters": {}
}
Just sharing direct curl here may helpful 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
I'm trying to add a POST HTTP method to my AWS API Gateway. I'm using SAM framework with Python.
I find that there is a difference in the "body" of the response when it is generated from my desktop (curl or postman) and the AWS API Gateway 'TEST'
Right now, the "POST" command only prints the 'event' object received by the lambda_handler. (I'm using an object to store the event as you can see below)
def add(self):
response = {
"statusCode": 200,
"body": json.dumps(self._event)
}
return response
When I'm using the 'TEST' option of the API Gateway console, with the input:
{"username":"xyz","password":"xyz"}
I receive the following output:
{
"body": "{\"username\":\"xyz\",\"password\":\"xyz\"}",
<the rest of the response>
}
However, when I'm sending the curl (or postman) request:
curl --header "Content-Type: application/json" --request POST --data '{"username":"xyz","password":"xyz"}' <aws api gateway link>
I get the following response:
{
"body": "eyJ1c2VybmFtZSI6Inh5eiIsInBhc3N3b3JkIjoieHl6In0="
<the rest of the response>
}
Why do you think there is a difference between the two tests?
Curl and Postman seem to be automatically Base64 encoding your Authentication credentials.
The responses are the same. The latter response is a Base64-encoded token of the first response.
Is it possible to send request with: Content-Type: multipart/form-data to API Gateway?
In my case, I try to send form-data like below via Postman:
user[email]:extest829#ex.com
user[password]:password
user[password_confirmation]:password
user[username]:testUser
But It seems that API Gateway loses the content.
Everything works fine when I send it as: application/x-www-form-urlencoded or application/json.
Using mulipart/form-data is not fully supported by AWS API Gateway, especially when we try to send file via mulipart/form-data.
To send image along with other data from form, probably the best solution would be send it as JSON, where image is encoded with base64.
For example, when someone want to send:
Username (string)
Avatar (image)
Avatar should be encoded with base64. It gives an image as a text, like:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyA...
The content of POST message would be:
{
"user_account": {
"avatar": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyA...",
"username": "my name"
}
}
API Gateway
In API Gateway, under your API, open Models and create new model, for example UserAccount:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "UserAccountUpdate",
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"avatar": { "type": "string" },
"username": { "type": "string" }
}
}
}
}
In Method Request -> HTTP Request Headers set: Content-Type.
In Method Request -> Request Body set: application/json and as model use created UserAccount model.
In Integration Request -> Content Handling set as: Passthrough.
In Integration Request -> Body Mapping Templates choose: When no template matches the reuqest Content-Type header. (You can also use two other options here and set additional mapping templates).
Backend
Backend receives an image as a text encoded with base64. So probably before it uses futher, it needs to decode it from text to image.
Encoding/decoding images with base64 is quite popular, so you should find some appropriate tools / libs in your frameworks.
When you are sending request with Content-Type: multipart/form-data to API Gateway, you need to pass through your original Content-Type header to your integration endpoint.
aws apigateway update-integration \
--rest-api-id a1b2c3d4e5 \
--resource-id a1b2c3 \
--http-method POST \
--patch-operations op='replace',path='/requestParameters/integration.request.header.Content-Type',value='method.request.header.Content-Type'
Code example for managing binary data in AWS Gateway and Proxy+ Lambda. Or to upload and retrieve files from servers using AWS Gateway and Proxy Lambda+
Click here