I'm having an issue where I'm unable to do a GET Request to an AWS Amplify API even after seemingly configuring everything properly. Currently I'm using AWSMobileClient and the iOS Amplify SDK to develop an app:
AWSMobileClient.sharedInstance().getTokens { (tokens, err) in
NSLog("tokens: \(tokens.debugDescription)")
NSLog("tokens: \(tokens!.idToken!.claims.debugDescription)")
self.doInvokeAPI(token: tokens!.idToken!.tokenString!)
}
//...
func doInvokeAPI(token: String) {
let headerParameters = [
"Authorization" : token,
"Content-Type": "application/json",
"Accept": "application/json"
]
let queryParams = ["response" : "true"]
let request = RESTRequest(apiName: <ENDPOINT_NAME>, path: <PATH>, headers: headerParameters, queryParameters: queryParams, body: nil)
Amplify.API.get(request: request, listener: responseCallBack)
}
When I call Amplify.API.get(), I'm constantly getting a 403 Error, and after creating some helper functions (responseCallBack) to log the HTTP response, I'm receiving this, which shows it's an IncompleteSignatureException:
HTTP: <NSHTTPURLResponse: 0x283a580a0> { URL: <my-endpoint-url>/<my-path>?response=true } { Status Code: 403, Headers {
"Access-Control-Allow-Origin" = (
"*"
);
"Content-Length" = (
1158
);
"Content-Type" = (
"application/json"
);
Date = (
"Fri, 23 Oct 2020 21:22:06 GMT"
);
"access-control-allow-headers" = (
"*"
);
"x-amzn-errortype" = (
IncompleteSignatureException
);
"x-cache" = (
"Error from cloudfront"
);
} }
My amplifyconfiguration.json file looks like this:
{
"api": {
"plugins": {
"awsAPIPlugin": {
<MY_ENDPOINT_NAME>: {
"endpointType": "REST",
"endpoint": <MY_ENDPOINT_URL>,
"region": "us-west-2",
"authorizationType": "AMAZON_COGNITO_USER_POOLS"
},
<MY_OTHER_ENDPOINT_NAME>: {
"endpointType": "REST",
"endpoint": <MY_ENDPOINT_URL>,
"region": "us-west-2",
"authorizationType": "AMAZON_COGNITO_USER_POOLS"
}
}
},
},
"auth": {
"plugins": {
"awsCognitoAuthPlugin": {
"IdentityManager": {
"Default": {}
},
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": <IDENTITY_POOL_ID>,
"Region": "us-west-2"
}
}
},
"CognitoUserPool": {
"Default": {
"PoolId": <USER_POOL_ID>,
"AppClientId": <APP_CLIENT_ID>,
"Region": "us-west-2"
}
},
}
}
},
}
And my awsconfiguration.json looks like this:
{
"UserAgent": "aws-amplify/cli",
"Version": "1.0.5",
"IdentityManager": {
"Default": {}
},
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": <IDENTITY_USER_POOL_ID>,
"Region": "us-west-2"
}
}
},
"CognitoUserPool": {
"Default": {
"PoolId": <USER_POOL_ID>,
"AppClientId": <APP_CLIENT_ID>,
"Region": "us-west-2"
}
}
}
I can authenticate into my app (Auth.signIn() works) and Amplify.configure() in AppDelegate.swift doesn't seem to run into issues, since no errors occur when attempting to configure, so it looks like it passes that point. But when I try to call the API, I receive this error. I include the JWT token in the Authorization header when making the request, and have triple checked that I do not have typos. Does anyone have an idea as to why I cannot call the API?
Related
I get the following error while evaluating krakend on MacOS with latest from brew...
[KRAKEND] 2022/09/20 - 11:51:32.488 ▶ ERROR [ENDPOINT: /geo/v1/countries][JWTValidator] Unable to validate the token: should have a JSON content type for JWKS endpoint
My JWKS from keycloak running on AWS does seem to set the Content-Type properly so I do not understand the issue...
{
"$schema": "https://www.krakend.io/schema/v3.json",
"version": 3,
"name": "KrakenD - API Gateway",
"extra_config": {
"security/cors": {
"allow_origins": [
"*"
],
"expose_headers": [
"Content-Length",
"Content-Type"
],
"max_age": "12h",
"allow_methods": [
"GET",
"HEAD"
]
},
"telemetry/logging": {
"level": "DEBUG",
"prefix": "[KRAKEND]",
"syslog": false,
"stdout": true
}
},
"timeout": "3000ms",
"cache_ttl": "300s",
"output_encoding": "json",
"endpoints": [
{
"endpoint": "/geo/v1/countries",
"method": "GET",
"backend": [
{
"url_pattern": "/geo/v1/countries",
"is_collection": true,
"sd": "static",
"method": "GET",
"host": [
"https://api.sophware.com"
],
"disable_host_sanitize": false
}
],
"extra_config": {
"qos/ratelimit/router": {
"max_rate": 0,
"client_max_rate": 10,
"strategy": "header",
"key": "Authorization"
},
"auth/validator": {
"alg": "RS256",
"jwk_url": "https://auth.sophware.com/realms/sophware/protocol/openid-connect/certs",
"issuer": "https://auth.sophware.com/realms/sophware",
"operation_debug": true,
"cache": true
}
}
},
{
"endpoint": "/geo/v1/features",
"method": "GET",
"backend": [
{
"url_pattern": "/geo/v1/features",
"is_collection": true,
"sd": "static",
"method": "GET",
"host": [
"https://api.sophware.com"
],
"disable_host_sanitize": false
}
],
"extra_config": {
"qos/ratelimit/router": {
"max_rate": 0,
"client_max_rate": 5,
"strategy": "ip"
}
}
}
]
}
The error might be misleading because the JWT validation does not have a specific message when there are connectivity errors, but if you are sure the content is well-formed JSON, then the problem is mostly reaching the JWK URL.
I have the following settings defined, but I am still getting all put/get requests logged to my api, even though these are supposed to be "Microsoft".
Can anyone share advice?
"Serilog": {
"Using": [ "Serilog.Sinks.Console" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{ "Name": "Console" },
{
"Name": "Seq",
"Args": { "serverUrl": "http://logserver:5341" }
},
{
"Name": "File",
"Args": {
"path": "c:\\temp\\events.api.txt",
"rollingInterval": "Day"
}
}
],
"Properties": {
"Application": "Events API"
}
},
Example of a log:
[13:55:10 INF] Source:[::1] Request: PUT https localhost:44320/api
{json request object} Responded with [200] in 2ms
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration
.ReadFrom.Configuration(hostingContext.Configuration)
.Enrich.FromLogContext());
});
I want to stub and check the message body in POST request in mountebank,
{
"port": "22001",
"protocol": "http",
"name": "login_user",
"stubs": [
{
"responses": [
{
"is": {
"statusCode": 201,
"headers": {
"Content-Type": "application/json"
},
"body": {}
},
"_behaviors": {
"wait": 100
}
}
],
"predicates": [
{
"equals": {
"path": "/login_user",
"method": "POST",
"headers": {
"Content-Type": "application/json"
},
"body": {
"name": "Tony",
"age": "20"
}
}
}
]
}
]
}
if a message body in JSON format. expected response status Code 200.
for Example
{
"body": {
"name": "Tony",
"age": "20"
}
}
if a message body in JSON format but JSON string. expected response status Code 400.
for Example
{
"body": "{\"name\": \"Tony\", \"age\": \"20\"}"
}
You could achieve this with a 'matches' predicate containing a (pretty crude in this example) regex to capture any string input and return a 400:
"stubs": [
{
"responses": [
{
"is": {
"statusCode": 400,
"headers": {
"Content-Type": "application/json"
},
"body": {}
},
"_behaviors": {
"wait": 100
}
}
],
"predicates": [
{
"matches": {
"path": "/login_user",
"method": "POST",
"body": ".*\\\\\\\"name.*"
}
}
]
},
{
"responses": [
{
"is": {
"statusCode": 201,
"headers": {
"Content-Type": "application/json"
},
"body": {}
},
"_behaviors": {
"wait": 100
}
}
],
"predicates": [
{
"equals": {
"path": "/login_user",
"method": "POST",
"headers": {
"Content-Type": "application/json"
},
"body": {
"name": "Tony",
"age": "20"
}
}
}
]
}
]
Alternatively, you can also specify a default response code of 400 in the imposter declaration, so that anything that doesn't match a specific predicate will return a 400 response by default:
{
"port": "22001",
"protocol": "http",
"name": "login_user",
"defaultResponse": {
"statusCode": 400
},
"stubs": [
{
.... snip ....
I have a .NET solution that uses a SAM template to generate cloudformation to deploy the stack. I am expecting the deployment - once complete - to have API Key Required = true on at least one of the methods. However after deployment, the keys and usage plans are created, but in the console the api key required is still set to false?
See below:
My SAM template:
"ServerlessRestApi": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Description":"This is a placeholder for the description of this web api",
"Body": {
"info": {
"version": "1.0",
"title": {
"Ref": "AWS::StackName"
}
},
"x-amazon-apigateway-api-key-source": "HEADER",
"paths": {
"datagw/general/table/get/{tableid}": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableResponse.Arn}/invocations"
}
},
"responses": {}
},
"security":[
{
"api_key":[]
}
]},
"securityDefinitions":{
"api_key":{
"type":"apiKey",
"name":"x-api-key",
"in":"header"
}
},
"/": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Get.Arn}/invocations"
}
},
"responses": {}
}
},
"/tables/{tableid}/{columnid}": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableBasic.Arn}/invocations"
}
},
"responses": {}
}
}
},
"swagger": "2.0"
}
}
},
I am not that familiar with swagger definitions, I know only the basics of SAM and CloudFormation. What am I missing here? I have reviewed other answers on stack overflow and believe I've copied the configuration correctly.
When I check the generated CloudFormation, my entries regarding x-api-key are not even present in the template?
"ServerlessRestApi": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Body": {
"info": {
"version": "1.0",
"title": {
"Ref": "AWS::StackName"
}
},
"paths": {
"datagw/general/table/get/{tableid}": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableResponse.Arn}/invocations"
}
},
"responses": {}
}
},
"/datagw/general/webhook/ccnotify": {
"post": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PostClickCollectNotification.Arn}/invocations"
}
},
"responses": {}
}
},
"/": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Get.Arn}/invocations"
}
},
"responses": {}
}
},
"/tables/{tableid}/{columnid}": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableBasic.Arn}/invocations"
}
},
"responses": {}
}
},
"/datagw/general/post/sohupdate": {
"post": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PostClickCollectStockUpdate.Arn}/invocations"
}
},
"responses": {}
}
}
},
"swagger": "2.0"
}
}
},
EDIT: This is what I have worked up to, but still API key required is not set to true in the API once the deployment has completed.
"ServerlessRestApi": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Description":"InSite Web API Version 2.0.0.0",
"Body": {
"swagger": "2.0",
"info": {
"version": "1.0",
"title": {
"Ref": "AWS::StackName"
}
},
"x-amazon-apigateway-api-key-source" : "HEADER",
"schemes":["https"],
"paths": {
"tables/query/{tableid}": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "GET",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableResponse.Arn}/invocations"
}
},
"responses": {},
"security": [
{
"api_key": []
}
]
}
},
"/products/update/": {
"post": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PostClickCollectStockUpdate.Arn}/invocations"
}
},
"responses": {}
}
},
"/": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "GET",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Get.Arn}/invocations"
}
},
"responses": {}
}
},
"/tables/{tableid}/{columnid}": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "GET",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableBasic.Arn}/invocations"
}
},
"responses": {}
}
}
},
"securityDefinitions": {
"api_key": {
"type": "apiKey",
"name": "x-api-key",
"in": "header"
}
}
}
}
},
So first off, if you are using the SAM framework, then why not try the serverless API (AWS::Serverless::Api) which has an Auth object where you can turn on ApiKeyRequired.
https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessapi
"ServerlessRestApi": {
"Type": "AWS::Serverless::Api",
"Properties": {
"Description":"InSite Web API Version 2.0.0.0",
"Auth": {
"ApiKeyRequired": "true"
},
"DefinitionBody": {
"swagger": "2.0",
"info": {
"version": "1.0",
"title": {
"Ref": "AWS::StackName"
}
},
"x-amazon-apigateway-api-key-source" : "HEADER",
"schemes":["https"],
"paths": {
"tables/query/{tableid}": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "GET",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableResponse.Arn}/invocations"
}
},
"responses": {},
"security": [
{
"api_key": []
}
]
}
},
"/products/update/": {
"post": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PostClickCollectStockUpdate.Arn}/invocations"
}
},
"responses": {}
}
},
"/": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "GET",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Get.Arn}/invocations"
}
},
"responses": {}
}
},
"/tables/{tableid}/{columnid}": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "GET",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableBasic.Arn}/invocations"
}
},
"responses": {}
}
}
},
"securityDefinitions": {
"api_key": {
"type": "apiKey",
"name": "x-api-key",
"in": "header"
}
}
}
}
},
If for some reason you cannot use the serverless, you might be trying to overload the RestApi (which is fine, but you lose some of the other fine grain options). For full disclosure I do not work with API gateway in this way (I use the serverless transform) so this is all from reading the documentation and not from experiance.
I would try creating a bare bones AWS::ApiGateway::RestApi and then attach an AWS::ApiGateway::Method to the RestApi by reference it though RestApiId.
[1] https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-method.html
I think you are missing the "securityDefinitions":
Body:
swagger: "2.0"
...
...
securityDefinitions:
sigv4:
type: "apiKey"
name: "x-api-key"
in: "header"
x-amazon-apigateway-authorizer:
type: token
You can find here some more examples:
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-as-s3-proxy-export-swagger-with-extensions.html
I am new to WEBIDE, I am trying to consume northwind odata services, but so far I have been unsuccessful. Please see my code & help.
connection test on destination also was successful. but still I am getting error:
/V3/Northwind/Northwind.svc/$metadata", statusCode: 404, statusText:
"Not Found", headers: Array(0), body: "The resource you are looking
for has been removed,… its name changed, or is temporarily
unavailable."} responseText:"The resource you are looking for has been
removed, had its name changed, or is temporarily unavailable."
statusCode:404 statusText:"Not Found"
proto:Object
any suggestions, what I might be doing wrong?
neo-app.json:
{
"path": "/destinations/northwind",
"target": {
"type": "destination",
"name": "northwind"
},
"description": "Northwind OData Service"
}
manifest.json:
"sap.app": {
"id": "Mod3Act3",
"type": "application",
"i18n": "i18n/i18n.properties",
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"applicationVersion": {
"version": "1.0.0"
},
"dataSources": {
"northwind": {
"uri": "/V3/Northwind/Northwind.svc/",
"type": "OData",
"settings": {
"odataVersion": "2.0"
}
}
}
},
"sap.ui5": {
"rootView": {
"viewName": "Mod3Act3.view.Main",
"type": "XML"
},
"dependencies": {
"minUI5Version": "1.30.0",
"libs": {
"sap.ui.core": {},
"sap.m": {},
"sap.ui.layout": {},
"sap.ushell": {},
"sap.collaboration": {},
"sap.ui.comp": {},
"sap.uxap": {}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"models": {
"": {
"dataSource": "northwind"
}
},
"resources": {
"css": [{
"uri": "css/style.css"
}]
}
}
controller
var url = "/V3/Northwind/Northwind.svc";
var oModel1 = new sap.ui.model.odata.ODataModel(url, true);
sap.ui.getCore().setModel(oModel1, "categoryList");
issue was with manifest.json.
"dataSources": {
"northwind": {
"uri": "/destinations/northwind/V3/Northwind/Northwind.svc/",
"type": "OData",
"settings": {"odataVersion": "2.0" }
}
}
this worked
please try the example from the sapui5 walk through:
manifest.json
{
"_version": "1.8.0",
"sap.app": {
...
"ach": "CA-UI5-DOC",
"dataSources": {
"invoiceRemote": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/",
"type": "OData",
"settings": {
"odataVersion": "2.0"
}
}
}
},
"sap.ui": {
...
},
"sap.ui5": {
...
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "sap.ui.demo.walkthrough.i18n.i18n"
}
},
"invoice": {
"dataSource": "invoiceRemote"
}
}
}
}
controller
...
var oModel = this.getView().getModel("invoice");
...
please be aware of the accepting of the certificate due to the https connection and the same origin policy both mentioned in the linked walk through example.