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.
Related
We are using Microsoft Graph Search API to search through our O365 emails. Since the search only allows 25 results per request for mails. (see https://learn.microsoft.com/en-us/graph/api/resources/search-api-overview?view=graph-rest-beta#page-search-results)
We figured to work around this by batching our search request like this:
POST https://graph.microsoft.com/beta/$batch
{
"requests": [
{
"url": "/search/query",
"method": "POST",
"id": "MyMails-0",
"body":
{
"requests": [
{
"entityTypes": ["message"],
"query":
{
"query_string":
{
"query": "some search text"
}
},
"from": 0,
"size": 25
}
]
},
"headers":
{
"Content-Type": "application/json"
}
},
{
"url": "/search/query",
"method": "POST",
"id": "MyMails-1",
"body":
{
"requests": [
{
"entityTypes": ["message"],
"query":
{
"query_string":
{
"query": "some search text"
}
},
"from": 25,
"size": 25
}
]
},
"headers":
{
"Content-Type": "application/json"
}
},
{
"url": "/search/query",
"method": "POST",
"id": "MyMails-2",
"body":
{
"requests": [
{
"entityTypes": ["message"],
"query":
{
"query_string":
{
"query": "some search text"
}
},
"from": 50,
"size": 25
}
]
},
"headers":
{
"Content-Type": "application/json"
}
},
{
"url": "/search/query",
"method": "POST",
"id": "MyMails-3",
"body":
{
"requests": [
{
"entityTypes": ["message"],
"query":
{
"query_string":
{
"query": "some search text"
}
},
"from": 75,
"size": 25
}
]
},
"headers":
{
"Content-Type": "application/json"
}
}
]
}
This works usually well, but in some cases the API returns something like this:
{
"id": "MyMails-2",
"status": 400,
"headers":
{
"Link": "<https://developer.microsoft-tst.com/en-us/graph/changes?$filterby=beta,RemoveDeprecatedUnderscoreProperty&from=2021-12-01&to=2022-01-01>;rel=\"deprecation\";type=\"text/html\",<https://developer.microsoft-tst.com/en-us/graph/changes?$filterby=beta,RemoveDeprecatedUnderscoreProperty&from=2021-12-01&to=2022-01-01>;rel=\"deprecation\";type=\"text/html\",<https://developer.microsoft-tst.com/en-us/graph/changes?$filterby=beta,RemoveDeprecatedUnderscoreProperty&from=2021-12-01&to=2022-01-01>;rel=\"deprecation\";type=\"text/html\"",
"Deprecation": "Tue, 14 Dec 2021 23:59:59 GMT",
"Sunset": "Sat, 31 Dec 2022 23:59:59 GMT",
"Cache-Control": "no-cache",
"Content-Type": "application/json"
},
"body":
{
"error":
{
"code": "BadRequest",
"message": "\r\n An exception occurred\r\n Lss call failed with status code 400. \"Exchange service returned error ErrorExecuteSearchStaleData: Please reissue the query with rowOffset = 0. The specified rowoffset is '50', but the results are stale.\".",
"innerError":
{
"date": "2022-01-25T09:58:53",
"request-id": "75def95f-a857-427d-a8b4-ee2792329e87",
"client-request-id": "75def95f-a857-427d-a8b4-ee2792329e87"
}
}
}
}
I noticed the deprecation note in the header, however I can't find anything about it. Neither about the actual exception.
What am I missing?
[workaround]
Thanks for the hint #user2250152.
This heavily reduced the issue by splitting the request into two requests, while the second is able to request more than 25 mails at a time:
POST https://graph.microsoft.com/beta/$batch
{
"requests": [
{
"url": "/search/query",
"method": "POST",
"id": "MyMails-0",
"body": {
"requests": [
{
"entityTypes": [
"message"
],
"query": {
"query_string": {
"query": "some search text"
}
},
"from": 0,
"size": 25
}
]
},
"headers": {
"Content-Type": "application/json"
}
},
{
"url": "/search/query",
"method": "POST",
"id": "MyMails-1",
"body": {
"requests": [
{
"entityTypes": [
"message"
],
"query": {
"query_string": {
"query": "some search text"
}
},
"from": 25,
"size": 200
}
]
},
"headers": {
"Content-Type": "application/json"
}
}
]
}
The error with stale results can happen time to time.
You can decrease the number of batch requests to reduce a chance that the error with stale results will occur.
For the first page "from": 0 the max size is 25. But for the next page "from": 25 you can increase the page size to 200.
I've tested the search query with "from": 25 and "size": 200 and it returns 200 results.
Resources:
Page search results
Swagger execution works but it displays "unvalid" for multiple required propreties.
this is the error message:
{"messages":["attribute paths.'/smile_video'(post).requestBody.content.'multipart/form-data'.schema.required is not of type `array`"],"schemaValidationMessages":[{"level":"error","domain":"validation","keyword":"oneOf","message":"instance failed to match exactly one schema (matched 0 out of 2)","schema":{"loadingURI":"#","pointer":"/definitions/Operation/properties/requestBody"},"instance":{"pointer":"/paths/~1smile_video/post/requestBody"}}]}
This is the request body definition:
"requestBody": {
"required": true,
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"required": [
"video",
"encodings"
],
"properties": {
"video": {
"type": "string",
"format": "binary",
"description": "Upload video file"
},
"encodings": {
"type": "string",
"format": "binary",
"description": "Upload video file "
}
}
}
}
}
}
This is the swagger screenshot
The solution is to disable validation by adding validatorUrl : false
const ui = SwaggerUIBundle({
url: "***",
dom_id: '#swagger-ui',
deepLinking: true,
validatorUrl : false,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
]
});
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 ....
Have an MS Flow trying to call the Graph API to update a user's profile photo. It takes a username and jpg photo file and then calls an HTTP connection secured using Azure AD (with https://graph.microsoft.com as the resource URI). Unfortunately, I get the error The file you chose isn't an image. Please choose a different file. which seems to indicate that I am not posting the file encoded in a way that MS Graph recognizes.
I've tried all variations I can think of with the body (using the #binary, #base64ToBinary, etc):
"body": "#{triggerBody()?['file']?['contentBytes']}"
to try to get it to treat "correctly", but with no luck.
This is the full flow definition:
{
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
},
"$authentication": {
"defaultValue": {},
"type": "SecureObject"
}
},
"triggers": {
"manual": {
"type": "Request",
"kind": "Button",
"inputs": {
"schema": {
"type": "object",
"properties": {
"file": {
"title": "Photo",
"type": "object",
"x-ms-dynamically-added": true,
"description": "Please select file or image",
"x-ms-content-hint": "FILE",
"properties": {
"name": {
"type": "string"
},
"contentBytes": {
"type": "string",
"format": "byte"
}
}
},
"text": {
"title": "Username",
"type": "string",
"x-ms-dynamically-added": true,
"description": "user#domain.com",
"x-ms-content-hint": "TEXT"
}
},
"required": [
"text"
]
}
}
}
},
"actions": {
"Invoke_an_HTTP_request": {
"runAfter": {},
"metadata": {
"flowSystemMetadata": {
"swaggerOperationId": "InvokeHttp"
}
},
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"name": "#json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$connections']['webcontents_1']['connectionId']"
}
},
"method": "post",
"body": {
"method": "PUT",
"url": "https://graph.microsoft.com/v1.0/users/#{triggerBody()['text']}/photo/$value",
"headers": {
"Content-Type": "image/jpeg"
},
"body": "#{triggerBody()?['file']?['contentBytes']}"
},
"path": "/codeless/InvokeHttp",
"authentication": {
"type": "Raw",
"value": "#json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"
}
}
}
}
}
and the full error:
{
"error": {
"code": 502,
"message": "{\r\n \"error\": {\r\n \"code\": 502,\r\n \"source\": \"unitedstates-002.azure-apim.net\",\r\n \"clientRequestId\": \"e105d9f2-af13-4a5b-8fbd-c84c49cadc8f\",\r\n \"message\": \"BadGateway\",\r\n \"innerError\": {\r\n \"error\": {\r\n \"code\": \"ErrorInternalServerError\",\r\n \"message\": \"An internal server error occurred. The operation failed., The file you chose isn't an image. Please choose a different file.\",\r\n \"innerError\": {\r\n \"request-id\": \"e3214f20-8592-4fb0-9d34-677322b231ae\",\r\n \"date\": \"2019-07-30T21:42:10\"\r\n }\r\n }\r\n }\r\n }\r\n}"
}
}
I have the following simple swagger.json file. This is generated using go-swagger annotations for a golang service. I am able to get the UI page running with redoc.
I want to display it with swagger-ui but I cannot get it to work. It shows an error in console on the page load that says
Uncaught TypeError: Cannot create property 'definitions' on string 'swagger.json'(…)
window.swaggerUi = new SwaggerUi({
spec: "swagger.json",
dom_id: "swagger-ui-container",
supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'],
onComplete: function(swaggerApi, swaggerUi){
log("Loaded UI")
},
onFailure: function(data) {
log("Unable to Load SwaggerUI");
},
docExpansion: "none",
jsonEditor: false,
defaultModelRendering: 'schema',
showRequestHeaders: false
});
window.swaggerUi.load();
Not sure why that is happening
The redoc page displays as follows
This is the swagger file
{
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"schemes": [
"http",
"https"
],
"swagger": "2.0",
"info": {
"description": "the purpose of this service is to do a health check",
"title": "Health Check API.",
"termsOfService": "TOS",
"contact": {
"name": "Backend",
"email": "Backend#company.com"
},
"license": {
"name": "Company Licence"
},
"version": "0.0.1"
},
"host": "host.com",
"basePath": "/",
"paths": {
"/health": {
"get": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"schemes": [
"http",
"https"
],
"summary": "Health check route.",
"operationId": "health",
"responses": {}
}
}
},
"definitions": {}
}
From SwaggerUI docs, it seems that it expects
A JSON object describing the OpenAPI Specification
as a value of spec parameter.
You should use url if you want to provide it with url:
window.swaggerUi = new SwaggerUi({
url: "swagger.json", // <----------------- change to url here
dom_id: "swagger-ui-container",
supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'],
onComplete: function(swaggerApi, swaggerUi){
log("Loaded UI")
},
onFailure: function(data) {
log("Unable to Load SwaggerUI");
},
docExpansion: "none",
jsonEditor: false,
defaultModelRendering: 'schema',
showRequestHeaders: false
});
window.swaggerUi.load();