I'm now developing REST API with Cloud endpoints and App engine.
I will like to implement api key authentication but it does not work.
Looks good without query params of 'key=${API KEY}'.
# curl -X POST https://hogehoge.com/test -d '{"key":"value"}'
{
"code": 16,
"message": "Method doesn't allow unregistered callers (callers without established identity). Please use API Key or other form of API consumer identity to call this API.",
"details": [
{
"#type": "type.googleapis.com/google.rpc.DebugInfo",
"stackEntries": [],
"detail": "service_control"
}
]
}
But any key can be granted to access to the backend.
# curl -X POST https://hogehoge.com/test?key=aaa -d '{"key":"value"}'
POST is sended.
Of course, API key generated via API management will work.
# curl -X POST https://hogehoge.com/test?key=${realkey} -d '{"key":"value"}'
POST is sended.
Cloud endpoint file definition is
swagger: "2.0"
info:
title: "xxxxxxxxx"
description: "xxxxxxxxx"
version: "1.0.0"
host: "hogehoge.com"
schemes:
- "https"
security: []
paths:
"/test":
post:
description: "test"
operationId: "test"
security:
- api_key: []
parameters:
- name: body
in: body
required: true
schema:
$ref: '#/definitions/testRequest'
responses:
201:
description: "Success"
schema:
$ref: '#/definitions/testResponse'
definitions:
testRequest:
type: object
required:
- data
properties:
data:
type: object
required:
- key
properties:
token:
type: string
example: value
maxLength: 20
testResponse:
type: string
securityDefinitions:
api_key:
type: "apiKey"
name: "key"
in: "query"
What I expect is only key generated via API management will be granted to access.
Let me know how to solve this issue.
Thanks.
It seems that the Service Control API might not be enabled on your project.
In order to check that, you can run
gcloud services list --enabled
If servicecontrol.googleapis.com is not listed in the result of the previous command, you should run
gcloud services enable servicecontrol.googleapis.com
Furthermore, you could check that you have all the required services for Endpoints enabled. You can see how to do this in the documentation
Related
I have Cloud Gateway API that connect to Cloud Function.
It worked great with an API key that I generated, but then when I restricted the key to enable access for my specific domain only - example.com, I started to get CORS errors on the client. ( it did worked without domain restriction)
So I enabled CORS in the config file in the Console, the file had no errors, but I still get a CORS error when accessing the API URL from my domain with the key:
https://project-xxxx.uc.gateway.dev/search?key=AIxxxxxxxxx
Config :
swagger: "2.0"
info:
title: projectapi
description: "data api"
version: "1.0.0"
schemes:
- "https"
host: "project-xxxxxxxx.apigateway.xxxxx-xxxxx.cloud.goog"
x-google-endpoints:
- name: "project-xxxxxxxx.apigateway.xxxxx-xxxxx.cloud.goog"
allowCors: True
paths:
"/search":
get:
description: "data"
operationId: "project"
x-google-backend:
address: https://us-central1-projectName.cloudfunctions.net/search
security:
- api_key: [key]
responses:
200:
description: "Success."
schema:
type: string
400:
description: "Invalid"
securityDefinitions:
api_key:
type: "apiKey"
name: "key"
in: "query"
My Cloud Function do allow CORS, and works great if called directly with the link here in the address key.
Why this config wont allow cors for the Gateway ?
Solved !
You must enable the key not only for your domain name, but also for your specific API name from the list, go to APIs & Services => Credentials => API keys => your key => API restrictions => choose your API name from the list !
This allow access to a Function from a specific domain - without using a Balancer.
I am trying to set up a GraqphQL Server, on Cloud Functions, and I want to set up an API Gateway to handle authentication with auth0 and jwt....
I have it working from the tutorial, the problem is it always requires a JWT token, where as I want some GraphQL queries to be available publicly, and if the user signs in they get more access...
From my understanding the way you do this is by using two authentications in the security settings, where one is the JWT and one is empty, however the API Gateway seems to always want the JWT token... Here is my open API spec, maybe someone has an idea?
swagger: '2.0'
info:
title: <redacted>-graphql-api
description: Basic GraphQL Open APISchema
version: 1.0.0
schemes:
- https
produces:
- application/json
securityDefinitions:
auth0_jwk:
authorizationUrl: "<redacted>"
flow: "implicit"
type: "oauth2"
# Replace YOUR-ACCOUNT-NAME with your Auth0 account name.
x-google-issuer: "<redacted>"
x-google-jwks_uri: "<redacted>"
# Optional. Replace YOUR-CLIENT-ID with your client ID
x-google-audiences: "<redacted>"
paths:
/:
post:
summary: GraphQL endpoint
operationId: gql
x-google-backend:
address: <redacted> # App URL/endpoint
responses:
'200':
description: A successful response
schema:
type: object
security:
- {}
- auth0_jwk: []
get:
summary: GraphQL Playground
operationId: playground
x-google-backend:
address: <redacted> # App URL/endpoint
responses:
'200':
description: A successful response
schema:
type: string
Having an issue with displaying xml structure defined in swagger file on cloud endpoint portal (Developer portal) for example it does not show the namespaces and example defined, but it works fine when uploaded on swagger editor
Following is example of xml definition declared
MsgResp:
type: object
properties:
Code:
type: string
example: RC_001_SUCCESS
Message:
type: string
example: Message sent
xml:
name: 'MessageResponse'
wrapped: true
namespace: http://MsgResponse
Edit:
Swagger file
# [START swagger]
swagger: '2.0'
info:
title: <Endpoint-name>
description: <Endpoint-name>
version: 1.0.0
# Connects to the cloud run running the ESP Beta 2 image
host: <Endpoint-address> # CloudRun/Esp url
security: []
schemes:
- https
paths:
"/status":
post:
description: "Test API for sending request from system 1 to IIP. "
operationId: "status-api"
# Defines which service it should connect to for backend processing, It can be Cloud function/ Cloud Run url
x-google-backend:
address: https://<Function1-address> # Backend Cloud function URL
deadline: 3600.0
# Defines Authentication mechanism to use, Following mentions to use API KEYS
security:
- api_key: []
# MIME Types expected as request and response
produces:
- "application/xml"
consumes:
- "application/xml"
parameters:
- in: body
name: schema
description: Input Schema for /status
schema:
$ref: '#/definitions/InSchema'
responses:
200:
description: OK
schema:
$ref: '#/definitions/MessageResponse'
404:
description: Not Found
500:
description: Internal Service Error
definitions:
InSchema:
type: object
xml:
name: 'Identifier'
prefix: 'msg'
wrapped: true
namespace: 'http://Identifier'
properties:
Number:
type: integer
LogIdentifier:
type: object
properties:
Code:
type: integer
Type:
type: string
xml:
name: 'LogicalIdentifier'
wrapped: true
namespace: http://LogicalIdentifier
prefix: sample
example: # <----------
Number: 38
LogIdentifier:
Code: 100
Type: CDC
MessageResponse:
type: object
properties:
Code:
type: string
example: SUCCESS
Message:
type: string
example: Message sent
# [START securityDef]
securityDefinitions:
api_key:
type: "apiKey"
name: "key"
in: "query"
# [END securityDef]
As seen on swagger editor
As seen on Cloud endpoint portal/ application portal
According to Cloud Endpoints on Cloud Run Official Documentation, I can only see the .json MimeType is used in the example.
The Cloud Endpoint service definition should be based on OpenAPI Specification v2.0, also known as Swagger 2, which describes the surface of your backend service and any authentication requirements.
So checking the OpenAPI Specification v2.0 in GitHub, I was not able to see xml specification in the MimeType Section. However in the Swagger Official Documentation, I can see that the xml media type is supported as well.
So I would like to ask you to check all the steps provided in the Cloud Endpoint on Cloud Run Official Documentation.
In the screenshot, I can see 404 NOT_FOUND error, this error is mentioned in the Troubleshooting section of Cloud Endpoints, so please have a look into it.
My setup contains google-endpoints with google-cloud-functions as my backend.
Google endpoints is defined with the following swagger v2 yaml:
swagger: "2.0"
info:
description: "yada..."
version: "0.0.1"
title: "yadada.."
termsOfService: "http://swagger.io/terms/"
contact:
name: "blah"
email: "email#mail.com"
url: "https://example.com"
host: "(generated service url by google when endpoints is deployed, i.e. 'api-gateway-xyz123123-ew.a.run.app')"
tags:
- name: "Documents"
description: "blah"
schemes:
- "https"
paths:
/api/documents:
post:
tags:
- "Documents"
summary: "Add a new document"
description: ""
security:
- firebase: []
operationId: "addDocument"
x-google-backend:
address: "(cloud functions http url)/documents"
consumes:
- "application/json"
produces:
- "application/json"
parameters:
- in: "body"
name: "body"
description: "Document supplied"
required: true
schema:
$ref: "#/definitions/Document"
responses:
201:
description: "The document was successfully created."
schema:
$ref: "#/definitions/Document"
400:
description: "Invalid input. See response for details"
schema:
items:
$ref: "#/definitions/Error"
/api/documents/{document_id}:
get:
tags:
- "Documents"
summary: "Get a document with the given ID"
description: ""
security:
- firebase: []
operationId: "getDocument"
x-google-backend:
address: "(cloud function http url)/documents/"
path_translation: APPEND_PATH_TO_ADDRESS
produces:
- "application/json"
parameters:
- in: "path"
name: "document_id"
description: "ID of the document to modify"
required: true
type: "string"
responses:
200:
description: "success."
schema:
type: "array"
items:
$ref: "#/definitions/Document"
404:
description: "Document not found"
schema:
items:
$ref: "#/definitions/Error"
securityDefinitions:
firebase:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://securetoken.google.com/%%GOOGLE_PROJECT_ID%%"
x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken#system.gserviceaccount.com"
x-google-audiences: "%%GOOGLE_PROJECT_ID%%"
definitions:
(a lot of type definitions)
This works with the POST endpoint without any problems.
The problem is with the GET REST endpoint where the path variable is not passed correctly to the backend.
As in https://cloud.google.com/endpoints/docs/openapi/openapi-extensions I tried to add the x-google-backend parameter as in the swagger api above. (path_translation: APPEND_PATH_TO_ADDRESS).
However this does not work.
I get an Unauthorized Error (403) as the cloud function is not hit by the endpoints frontend.
Currently I use an ugly workaround without the path_translation parameter which translates the google endpoints path variable to a query parameter in the cloud function backend with the same name. I.e. in the backend the url /documents?document_id=xyz is called.
(What I try to achieve is to pass the call with the backend url /documents/{document_id})
Does anyone know how to configure path based parameters correctly so that they are passed correctly to the cloud function backend?
Thank you in advance.
Regards,
Sebastian
TL;DR:
I assume that your 403 error isn't the correct error. It should be a 404, but because the endpoint is unknown, I guess that 403 is answered.
Cloud Endpoint is frustrating about this behavior. With the path_translation: APPEND_PATH_TO_ADDRESS, you think that your final called address will be /documents/{document_id}, but NO. The full openAPI path is append to your backend address, in your case: /documents/api/documents/{document_id}
That's why the endpoint doesn't exist and you should have a 404 (and not a 403).
For more details, you can have a look to this page.
Note: I'm in relation with Google team on this topic, and it will take time before having an update on this behavior.
I want to add a security definition to an API to run it in the google cloud scheduler (using OIDC token, and a service account).My openapi.yml looks like this
"/common/test":
post:
description: "test"
operationId: "test"
responses:
200:
description: "Success"
400:
description: "Fail"
security:
- service_account: []
securityDefinitions:
service_account:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "xx#example.iam.gserviceaccount.com"
x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/xx#example.iam.gserviceaccount.com"
but it fails when I called this API via cloud scheduler(using OIDC token, and a service account(xx#example.iam.gserviceaccount.com)). log view says unauthorized 401. How can I fix this error.
{httpRequest: {status: 401} insertId: "1r9kx9lf2jy71o" jsonPayload: { #type: "type.googleapis.com/google.cloud.scheduler.logging.AttemptFinished" jobName: "projects/project-xxx/locations/us-central1/jobs/test" status: "UNAUTHENTICATED" targetType: "HTTP" url: "https://project-xxx.appspot.com/common/test/"} logName: "projects/project-xxx/logs/cloudscheduler.googleapis.com%2Fexecutions" receiveTimestamp: "2020-01-06T06:30:01.000238320Z" resource: { labels: {…} type: "cloud_scheduler_job" }severity: "ERROR" timestamp: "2020-01-06T06:30:01.000238320Z"}
OIDC (openConnectId) tokens, from Cloud Scheduler, are not compatible with Oauth2 authorization. OpenAPI v3 has added support for OIDC tokens.