I am trying to figure out how to get Express Gateway to use the Auth Bearer token in request, upstream to the api service.
Below is my config as of right now.
http:
port: 8080
admin:
port: 9876
host: localhost
apiEndpoints:
api:
host: localhost
paths:
- '/truck-api/*'
- '/car-api/*'
serviceEndpoints:
truck-service:
url: 'http://10.0.0.2:5010/api'
car-service:
url: 'http://10.0.0.2:5011/api'
policies:
- basic-auth
- cors
- expression
- key-auth
- log
- oauth2
- proxy
- rate-limit
- rewrite
- request-transformer
pipelines:
default:
apiEndpoints:
- api
policies:
- proxy:
-
condition:
name: pathMatch
pattern: "^/truck-api/(.*)"
action:
serviceEndpoint: truck-service
prependPath: true
ignorePath: false
stripPath: true
changeOrigin: true
-
condition:
name: pathMatch
pattern: "^/car-api/(.*)"
action:
serviceEndpoint: car-service
prependPath: true
ignorePath: false
stripPath: true
changeOrigin: true
The frontend calls express gateway with a proper auth bearer token, however the express gateway doesn't forward that auth bearer token on to the upstream service.
Advice?
After some digging and a lot of trial and error the solution was relatively simple, use request transformer.
added this to the policies section:
- request-transformer:
- action:
headers:
remove: ['Authorization']
add:
Authorization: "'Bearer ***'"
For me remove: ['Authorization'] did not work.
I was authenticating towards express gateway using:
"Authorization: apiKey ${keyId}:${keySecret}" and authenticating towards backend service by using Authorization: "'Bearer ***'" added by request-transformer. I would expect remove: ['Authorization'] would remove "Authorization: apiKey ${keyId}:${keySecret}", after I was already successfully authenticated at express gateway and add: Authorization: "'Bearer ***'" would add new Authorization header so newly constructed request would replace apiKey with Bearer token but using remove: ['Authorization'] resulted in failure to authenticate at express gateway.
I resolved this issue by changing HTTP header used for authorization at express gateway side with apiKeyHeader (https://www.express-gateway.io/docs/policies/key-authorization/).
policies:
- request-transformer:
- action:
headers:
add:
# pass oauth2 token
Authorization: "'Bearer ***'"
- key-auth:
- action:
# arbitrarily rename default header name from Authorization
apiKeyHeader: open_sesame
The open_sesame header grants us access to api gateway and request-transformer adds authorization header with proper token to the request for accessing the backend service.
curl -v -H "open_sesame: apiKey ${keyId}:${keySecret}"...
Related
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
I'm using gcp api gateway for JWT authentication. after generating a token from my auth service and then putting it in postman I always receive this response no matter what I put in the 'aud' part of the token:
Here is my open api file:
# openapi2-run.yaml
swagger: '2.0'
info:
title: my-gateway-id
description: Sample API on API Gateway with a Cloud Run backend
version: 1.0.0
schemes:
- https
produces:
- application/json
x-google-backend:
address: https://my-cloud-run.a.run.app
jwt_audience: https://my-cloud-run.a.run.app
securityDefinitions:
jwt_auth:
authorizationUrl: ''
flow: 'implicit'
type: 'oauth2'
x-google-issuer: 'id-admin#my-project.iam.gserviceaccount.com'
x-google-jwks_uri: 'https://www.googleapis.com/service_accounts/v1/metadata/x509/id-admin#my-project.iam.gserviceaccount.com'
paths:
/:
post:
security:
- jwt_auth: []
summary: GraphQL endpoint
operationId: gql
responses:
'200':
description: A successful response
schema:
type: object
I've looked over and over the docs and can't see what's going on? thanks in advance.
You get 403 because the aud on the JWT token you've generated is not found on securityDefinitions of your API config.
To allow additional client IDs to access the backend service, you can specify the allowed client IDs in the x-google-audiences field by using comma-separated values. API Gateway then accepts the JWTs with any of the specified client IDs in the aud claim.
Go here and paste your token to see your JWT "aud" claim. If you generated the ID token using gcloud auth, the aud will most likely be a Client ID like 1234567890.apps.googleusercontent.com. But if you generated the token using your own service, then it would depend on what you've specified as a target audience.
To solve the problem, add x-google-audiences field on the securityDefinitions section and the value should match with your JWT "aud" claim.
Assuming that the aud on your JWT token is a Cloud Run service endpoint, then your API config should look like this. Feel free to check the documentation as additional reference:
x-google-backend:
address: https://my-cloud-run.a.run.app
securityDefinitions:
jwt_auth:
authorizationUrl: ''
flow: 'implicit'
type: 'oauth2'
x-google-issuer: 'id-admin#my-project.iam.gserviceaccount.com'
x-google-jwks_uri: 'https://www.googleapis.com/service_accounts/v1/metadata/x509/id-admin#my-project.iam.gserviceaccount.com'
x-google-audiences: 'https://my-cloud-run.a.run.app'
If you have multiple audiences, then it should be a single string separated by a comma. Spaces aren't allowed between the audiences.
I was building authenticated Cloud functions usingCloud functions with ESPV2 and Firebase authentication and API Management. Once I got the JWT token from firebase after authentication, I tried curl to the link with the token in Authorization as Bearer. I got 'JWT verification fails' when I tried in postman. I got 'Bad Request' when I tried it from my client application. Other than the setup mentioned in the links, do I need to do anything extra before I make the request?
Update with more details as requested
swagger: "2.0"
info:
title: My API Endpoints
description: My API Endpoints
version: 1.0.0
host: myapi-abcdefg.a.run.app
schemes:
- https
produces:
- application/json
securityDefinitions:
firebase:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://securetoken.google.com/fan-demand"
x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken#system.gserviceaccount.com"
x-google-audiences: "my-google-project-id"
paths:
/getevents:
get:
summary: Get Events
operationId: getevents
x-google-backend:
address: https://us-central1-my-google-project-id.cloudfunctions.net/getevents
protocol: h2
security:
- firebase: []
responses:
"200":
description: A successful response
schema:
type: string
"403":
description: Failed to authenticate
After deploying this service, I get the id token from Firebase using the getIdToken() method in the Firebase Dart SDK. The JWT token is in the Header.payload.tail format. Then I added the token in the Authorization header with Bearer + id token and I get the following response.
Update:
I tried the new API Gateway product using https://cloud.google.com/api-gateway/docs/authenticating-users-firebase instead of ESP.
My configuration:
swagger: "2.0"
info:
title: My API Endpoints
description: My API Endpoints
version: 1.0.0
schemes:
- https
produces:
- application/json
securityDefinitions:
firebase:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://securetoken.google.com/my-project"
x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken#system.gserviceaccount.com"
x-google-audiences: "my-project"
paths:
/getevents:
get:
summary: Get Events
operationId: getevents
x-google-backend:
address: https://us-central1-my-project.cloudfunctions.net/getevents
security:
- firebase: []
responses:
"200":
description: A successful response
schema:
type: string
"403":
description: Failed to authenticate
Client Side Code:
Client side is developed in dart and user here is a firebase auth object from https://pub.dev/documentation/firebase_auth/latest/firebase_auth/User/getIdToken.html
user.getIdToken().then((token) async {
final response = await http.get(
Uri.parse(
'https://mygateway/getevents'),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token',
});
print('Token : ${token}');
print(response.body);
});
I got the response
403 Forbidden - Your client does not have permission to get URL
Without ESP
Cloud functions need to be deployed publicly (with allUsers) to be able to use firebase authentication.
Be careful:
Unlike Google Sign-in above, your function is doing the authentication;
therefore, you will be billed for unauthenticated requests since the function must do work to validate the token.
Link to relevant documentation
With ESP
If you want to use cloud functions with ESPv2 in front of it, you need to create a specific IAM for your ESP to be able to trigger privately your cloud functions.
To provide API management for Cloud Functions, you deploy the prebuilt ESPv2 container to Cloud Run.
You then secure your functions by using Cloud Functions IAM so that ESPv2 can invoke them.
Link to relevant documentation
I'm trying to add a new endpoint to an existing service, and while it shows on the API Gateway Resources page, it's not showing on the Stages page. Hitting the endpoint returns the header x-amzn-ErrorType as IncompleteSignatureException and an error that includes the JWT token and not a valid key=value pair (missing equal-sign) in Authorization header.
Our setup uses a swagger file to define the endpoints, and uses x-amazon-apigateway-integration to link the endpoint to the lambda function. On first deployment of the new endpoint, we had some problems as this integration was setup wrong, but has since been corrected to match the others (suspect this is where the problem lies).
I've tried making sure that the new endpoint config matches that of other working endpoints; I've removed the endpoint, redeployed, added it back and redeployed; I've renamed the lambda. None of these have worked.
The swagger file looks like:
/companies/{id}/info:
get:
consumes:
- application/json
produces:
- application/json
responses:
"200":
description: successful operation
headers:
Access-Control-Allow-Origin:
type: string
x-amazon-apigateway-integration:
uri:
Fn::Join:
- ""
- - Fn::Join:
- ""
- - "arn:aws:apigateway:"
- Ref: AWS::Region
- ":lambda:path/2015-03-31/functions/"
- Fn::GetAtt:
- GetCompanyInfoLambdaFunction
- Arn
- "/invocations"
httpMethod: POST
type: aws_proxy
post:
#... this method works fine with same config but different lambda
Any ideas as to how to fix this? Thanks
I'm kinda of new in EG. I have followed the documentation about issuing a jwt token instead of opaque but still receiving an opaque access token. Not sure what I'm missing to change.
This is my system.config file
db:
redis:
host: localhost
port: 6379
namespace: EG
crypto:
cipherKey: sensitiveKey
algorithm: aes256
saltRounds: 10
session:
secret: keyboard cat
resave: false
saveUninitialized: false
accessTokens:
timeToExpiry: 7200000
tokenType: 'jwt'
issuer: 'express-gateway'
audience: 'something'
subject: 'test'
secretOrPrivateKey: 'ssssst'
refreshTokens:
timeToExpiry: 7200000
authorizationCodes:
timeToExpiry: 300000
Already added a user and app with their own credentials (oauth2, basic-auth, jwt) without changing anything on the models.
this is my gateway.config file
http:
port: 8080
admin:
port: 9876
hostname: localhost
apiEndpoints:
api:
host: localhost
paths: '/api/*'
serviceEndpoints:
httpbin:
url: 'https://httpbin.org'
policies:
- jwt
- oauth2
- proxy
- rate-limit
pipelines:
default:
apiEndpoints:
- api
policies:
- oauth2:
action:
jwt:
issuer: express-gateway
audience: something
subject: test
secretOrPublicKey: ssssst
checkCredentialExistence: false
- proxy:
- action:
serviceEndpoint: httpbin
changeOrigin: true
the request for login is like this and secret is the keySecret generated with jwt credential of the app.
http://localhost:8080/oauth2/authorize?response_type=token&client_id=ae921ba9-7b4b-4c53-aaba-354bd6398e52&redirect_uri=http://localhost:3002/explorer&client_secret=0qOpBZkwO2ayQ8dO18yRuh
and the token response looks like this.
14070f7c4ffc49efb1fc1709cc4a7267|90c6efd2cf8342859756d8e3705417a3
Thanks for anyone who can help me.
The configuration looks correct. I've also personally tried the configuration you provided and I got back a JWT
Maybe you can try to set up a test project on Glitch.me so it's going to be easier to replicate locally.