i am not able to use authorization with cognito - amazon-web-services

I have configured my api to authorized against cognito user pool following is a example of the configuration.
getRecords:
handler: abc.def.GetRecords
events:
- http:
path: /getRecords
method: get
authorizer:
- {arn of coginito userPool}
When i pass access_token while calling the API i don't get response, but when i pass id_token it let me though with the authorisation, but i want it to work with access_token but not with id_token, Please help me to solve this usecase

Related

Amazon Cognito: add custom parameters to authorize URL when using OIDC identity provider

As stated in the title, I would like to add a custom parameter to the /authorize URL to which Cognito redirects when working with a OIDC User Pool Identity Provider (in my case https://example.xx.auth0.com/authorize).
I found out you can specify an authorize URL through cloudformation but it cannot contain query parameters.
More details:
Cognito is configured through Serverless (which uses Cloudformation under the hood):
Auth0IdentityProvider:
Type: AWS::Cognito::UserPoolIdentityProvider
Properties:
UserPoolId:
Ref: CognitoUserPool
ProviderType: "OIDC"
ProviderName: "Auth0"
ProviderDetails:
client_id: "xxxx"
client_secret: "xxxx"
attributes_request_method: "GET"
oidc_issuer: "https://xxxx.xx.auth0.com"
authorize_scopes: "openid profile email"
AttributeMapping:
email: "email"
When navigating to the Cognito hosted UI and selecting the Auth0 provider it redirects to the /authorize Cognito endpoint which in turn redirects to the /authorize Auth0 endpoint.
I need to add the connection parameter to Auth0's /authorize in order to bypass its UI and go straight to the social login but I haven't been able to find a way to do so.
Turns out that when configuring your Auth0 client you can specify the connection parameter and Auth0 will skip its UI for you, but it will only do that if the configured redirect_uri does not point to localhost.
auth0 = await createAuth0Client({
redirect_uri: window.location.origin,
scope: "openid profile email offline_access",
connection: "linkedin",
});

GCP API Gateway JWT always returning 403

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.

API Gateway not returning Response

I was trying GCP API Gateway using firebase authentication. I can see my request has been processed from the logs and completed with response code 200. However, I am not getting the response back to my client. I am getting the response when I call the function directly. Am I missing something ?
API Config
swagger: "2.0"
info:
title: API Endpoints
description: API Endpoints
version: 1.0.1
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:
/hello:
get:
summary: Test link
operationId: hello
x-google-backend:
address: https://us-central1-my-project.cloudfunctions.net/hello
security:
- firebase: []
responses:
"200":
description: A successful response
schema:
type: string
"403":
description: Failed to authenticate
Function
* Responds to any HTTP request.
*
* #param {!express:Request} req HTTP request context.
* #param {!express:Response} res HTTP response context.
*/
exports.helloWorld = (req, res) => {
let message = req.query.message || req.body.message || 'Hello World!';
res.status(200).send(message);
};
Logs
Additional Query
Initially, I had my functions private and was getting 403. It gave me 200 once I added allUsers with Cloud Functions Invoker to the permissions to the function I am trying to invoke. So I am a bit confused here. Part of the reason I am using API gateway with firebase auth is to protect it against unauthorised calls. And for firebase auth to work, I had to add allUsers, making it public. My understanding was that the API gateway alone would be public while all the backend services that it invokes would be private. In this case, the function can be directly invoked by anyone, rendering API Gateway useless. How can I setup the backend to private and only respond to authenticated calls through API gateway ?
Additional Logs
{
insertId: "8c13b49c-2752-4216-8188-d445f4724ef14850908905639612439#a1"
jsonPayload: {
api_key_state: "NOT CHECKED"
api_method: "1.myapi.GenerateRTCToken"
api_name: "1.myapi"
api_version: "1.0.1"
client_ip: "999.999.999.999"
http_method: "GET"
http_response_code: 200
location: "us-central1"
log_message: "1.myapi.GenerateRTCToken is called"
producer_project_id: "myproject"
request_latency_in_ms: 161
request_size_in_bytes: 4020
response_size_in_bytes: 579
service_agent: "ESPv2/2.17.0"
service_config_id: "myapi-config"
timestamp: 1606313914.9804168
url: "/generateRTCToken"
}
logName: "projects/myproject/logs/myapi%2Fendpoints_log"
receiveTimestamp: "2020-11-25T14:18:36.521292489Z"
resource: {
labels: {
location: "us-central1"
method: "1.myapi.GenerateRTCToken"
project_id: "myproject"
service: "myapi"
version: "1.0.1"
}
type: "api"
}
severity: "INFO"
timestamp: "2020-11-25T14:18:34.980416865Z"
}
To call the Google Cloud Function from the Api-Gateway without making it public you can grant the service account used by the API-Gateway the role CloudFunctions Invoker
On Creating an API config (4) : you set a service Account, take note of this service account.
Once you have identified the service account you can grant it the Cloud Funtions Invoker role to the service account. For these you can follow these steps:
Go to IAM&Admin
Look for the service account, and click on the pencil next to it( If you don't see the service account click on Add and type the service account email)
For role Select Cloud Functions Invoker
Click on Save
This will grant the service account the permission to call the functions without having them public.
I have an similar issue with API Gateway throwing the same response validating a token against keycloak.
The issue was with the JWT, it was too long, we remove unused roles from the user and work perfectly.
Hope it helps.
Take a look at this document where it is explained in detail how to use Firebase to authenticate in API Gateway.
In general there are two conditions that we need to keep on mind in order to configure these services:
When your client application sends an HTTP request, the authorization header in the request must contain the following JWT claims:
iss (issuer)
sub (subject)
aud (audience)
iat (issued at)
exp (expiration time)
To support Firebase authentication, add the following to the security definition in your API config:
securityDefinitions:
firebase:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
# Replace YOUR-PROJECT-ID with your project ID
x-google-issuer: "https://securetoken.google.com/YOUR-PROJECT-ID"
x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken#system.gserviceaccount.com"
x-google-audiences: "YOUR-PROJECT-ID"

Test GraphQL in AWS Unauthorized 401, problem with Authorizer

With Serverless I have this config:
functions:
my-account:
handler: src/index.handler
events:
- http:
path: /my-account
method: post
cors: true
authorizer:
name: authorizer
arn: arn:aws:cognito-idp:${self:provider.region}:XXXXXX:userpool/${self:custom.YYYY.cognito.userpool}
I'm trying to test with Postman but I got an:
{
"message": "Unauthorized"
}
I don't get what kind of Authorization it needs. I don't have API KEYs, I have a token in the app that consume that graphql, I put it as a "Bearer Token" but it still fails. Any advice?
You'll need to make a call first to Cognito to get a JWT token, then pass this in the request Authorization header as Bearer. I haven't used this route, but there's an API that does just that: InitiateAuth

Serverless AWS Lambda CORS Error

I am trying to do an http request from an angularjs app to a lambda function that I had setup using serverless.
Here is my serverless.yaml function
functions:
createcustomer:
handler: handler.createcustomer
events:
- http: post /createcustomer
cors: true
Create Customer Function
module.exports.createcustomer = (event, context, callback) => {
let customer = JSON.parse(event.body).customer;
service.create(customer, function(result) {
let response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Credentials": true,
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/json",
},
body: JSON.stringify({
result: 'Created Customer Successfully',
message: 'The account has been created!',
type: 'success',
customer: result
})
};
callback(null, response);
});
};
From my AngularJS app I call it like this
app.factory('MyFactory', ['$http', function($http) {
return {
CreateCustomer: function(customer) {$http.post('<apipath>/createcustomer', {customer:customer})}
}
}]);
However, I keep getting this error:
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:5000' is therefore not allowed access. The response had HTTP status code 403.
I have tried to enable CORS in the API Gateway on the POST method, but that did not change the outcome.
I've also tried setting CORS in the yaml file explicitly
functions:
createcustomer:
handler: handler.createcustomer
events:
- http: post /createcustomer
cors:
origin: '*'
Still no luck.
Does anyone know what I'm doing wrong here?
One weird thing is that I could get the post to work just fine through PostMan, but if I try it through my app it breaks.
Thanks
UPDATE
When I do serverless deploy it shows up in AWS like the picture above and the method looks like this
As I said before, I tried to enable CORS directly from the API Gateway console but there was no difference when I tried to call the method.
Your update with screenshots shows that the OPTIONS method is not set up for any of these resources. When you enable CORS for an API Gateway resource in the console, AWS sets this up automatically.
You can see this happen in the AWS console when you enable CORS for a resource, but, of course, your serverless deploy is overwriting this configuration.
To have the /createcustomer resource properly configured in AWS by the serverless deploy, you can rewrite this part of your serverless.yaml:
events:
- http: post /createcustomer
cors: true
To look like this:
events:
- http:
path: /createcustomer
method: post
cors: true
I'm not an expert in the framework's .yml syntax, so I can't explain exactly why this is.
Nonetheless, I've confirmed that a file like this:
functions:
deletecustomer:
handler: handler.deletecustomer
events:
- http:
path: /deletecustomer
method: post
cors: true
createcustomer:
handler: handler.createcustomer
events:
- http: post /createcustomer
cors: true
will create two resources in AWS API Gateway, one correctly configured for CORS, and one missing the OPTIONS method:
Here is the configuration that could help. Please note that it's always safe to be specific in allowing the CORS origins. So better to lock the origin down to localhost:{port-number}. In addition, you can also enable credentials on CORS settings. Please see the following serverless config as an example:
cors:
origin: 'http://localhost:4200'
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- X-Amz-User-Agent
allowCredentials: true
The cors configuration got moved up into the provider config:
provider:
httpApi:
cors: true