Cognito Access Token "cognito:groups" missing - amazon-web-services

I want to authenticate my API Gateway requests with Cognito.
For that i created custom scopes. API Gateway checks those scopes and proxies these requests to my Elastic Beanstalk API. This works fine.
But another part of my Authorization are groups. Based on a assigned group some actions have restricted Access. I need to use groups because i want to be able to add or remove those groups during user-lifecycle. The group will be checked in my Elastic Beanstalk API.
Problem
The documentation states that Access Tokens contain the cognito:groups claim. But a setup like in the Image below does not include this claim in my token.
The following decoded jwt will be produced after a login via hosted-UI. As you can see the claim is missing. ID tokens (with openid scope) will include this group. I am also sure that i've tested Cognito earlier with Amplify JS-SDK which included the group. But there i was unable to include my custom scopes.
{
"sub": "xxxxxxxxxxxxxxxxxxxxxx",
"token_use": "access",
"scope": "api.example.com/item.read api.example.com/item.write",
"auth_time": 1615325374,
"iss": "https://cognito-idp.eu-central-1.amazonaws.com/eu-central-1_xxxxxxx",
"exp": 1615328974,
"iat": 1615325374,
"version": 2,
"jti": "f37219a5-c8b0-411b-bdb3-ab7d9201b491",
"client_id": "xxxxxxxxxxxxxxx",
"username": "xxxxxxxxxxxxxxxxxxxxxxxxxx"
}
Do I miss about a restriction or configuration issue? Why is the group missing inside my Access Tokens?
Thanks for your help!

I had the same issue. The cognito:groups value appeared after I added the openid scope:
and the access token is still supplied, as per earlier comments.

Related

I can't get google cloud functions gen 2 to work with only authorized requests from behind a API Gateway

I recently switched to google cloud functions gen 2 and am having an issue with authentication via API Gateway. I have the new cloud function being called by my gateway with the function itself not allowing unauthorized users. The gateway has a service account attached to it with the cloud functions invoker role (and owner role since I'm troubleshooting).
The error message in the cloud function log is
The request was not authenticated. Either allow unauthenticated invocations or set the proper Authorization header. Read more at https://cloud.google.com/run/docs/securing/authenticating Additional troubleshooting documentation can be found at: https://cloud.google.com/run/docs/troubleshooting#unauthorized-client
I have a test function with the same code that uses cloud functions gen 1 and does not allow unauthenticated users. This function works great when you hit my api gateway. I also have a cloud function gen 2 that does allow unauthenticated users and that also works as expected when hitting the gateway, it's just my gen 2 that doesn't allow unauthenticated users.
For my API gateway yaml file, this is what the file looks like (with sensitive information XXX'd out),
swagger: "2.0"
info:
title: XXXXXXXX api gateway for carson blade analytics app
description: Sample API on API Gateway with a Google Cloud Functions backend
version: 1.0.0
schemes:
- https
produces:
- application/json
paths:
/convert_csv:
get:
summary: Converts an XLSX file to a CSV file
operationId: convert
x-google-backend:
address: https://convert-csv-XXXXX-ue.a.run.app
responses:
"200":
description: A successful response
schema:
type: string
When I hit the unauthenticated allowed one and look at it's headers, I see
{
"aud": "https://convert-csv-XXXXX-ue.a.run.app/",
"azp": "XXXX",
"email": "XXX#XXX.iam.gserviceaccount.com",
"email_verified": true,
"exp": 1660101164,
"iat": 1660097564,
"iss": "https://accounts.google.com",
"sub": "XXXXX"
}
with the email being the email that is associated with the service account that has the correct cloud function invoker role and the aud being the same address as the address in the cloud api yaml. So it's replacing the authentication header that I'm sending in with its service account one as expected. I've tried reading all the documentation and have tried a bunch of different yaml configurations, but I just can't figure this out.
To summarize, With each one being attached to a cloud api gateway and hitting the endpoint from postman, gen 2 with allow unauthenticated turned off -> doesn't work. gen 2 with allow unauthenticated turned on -> works. gen 1 with allow unauthenticated turned off -> works
Any help would be extremely appreciated, thanks.
Cloud Functions 2nd gen is a wrapper on top of Cloud Run. Many times, the 2 products are entangled.
You must have the Cloud Functions Invoker role AND the Cloud Run Invoker roles (your issue)
You can filter the logs by selecting Cloud Run service and not Cloud Functions
It's absolutely not clear, and from the beginning in the Alpha version. Despite my remarks to the PM and engineering team, the product has been publicly released and now there are a lot of mistakes and confusions because of this lack of clear separation. Too bad :(

AWS Cognito: where is the metadata URL of Cognito User Pool?

I'm trying to use AWS Cognito as an authorizer for my REST API in AWS API Gateway.
It asks me to fill in the Issuer URL:
Digging through the AWS Cognito User Pool page, there is no such thing.
I found a related answer here: AWS: Cognito integration with a beta HTTP API in API Gateway?
and I quote:
Issuer URL: Check the metadata URL of your Cognito User Pool
(construct the URL in this format :: https://cognito-idp.
[region].amazonaws.com/[userPoolId]/.well-known/openid-configuration
:: look for a claim named "issuer". Copy its Value and paste it here.
I can of course build the url as said above.
But still, where is the metadata URL of my Cognito User Pool????
Am I missing something really basic and being absolutely silly by asking this question?
Where is it??
This is driving me crazy.
The issuer URL of a Cognito User Pool has the following format:
https://cognito-idp.[region].amazonaws.com/[userPoolId]
As you stated correctly, you can get it from Cognito's well-known metadata endpoint, which is available at
https://cognito-idp.[region].amazonaws.com/[userPoolId]/.well-known/openid-configuration
This file is JSON-formatted and contains an issuer field, which contains the URL mentioned above. The whole file looks like this:
{
"authorization_endpoint":"https://cognito-idp.[region].amazonaws.com/[userPoolId]/authorize",
"id_token_signing_alg_values_supported":[
"RS256"
],
"issuer":"https://cognito-idp.[region].amazonaws.com/[userPoolId]",
"jwks_uri":"https://cognito-idp.[region].amazonaws.com/[userPoolId]/.well-known/jwks.json",
"response_types_supported":[
"code",
"token"
],
"scopes_supported":[
"openid",
"email",
"phone",
"profile"
],
"subject_types_supported":[
"public"
],
"token_endpoint":"https://cognito-idp.[region].amazonaws.com/[userPoolId]/token",
"token_endpoint_auth_methods_supported":[
"client_secret_basic",
"client_secret_post"
],
"userinfo_endpoint":"https://cognito-idp.[region].amazonaws.com/[userPoolId]/userInfo"
}

How to get application_default_credentials using service account?

I have a maven plugin which uses application_default_credentials.json file to authenticate against google cloud services.
I am trying to figure out to get default credential using service account instead of using my account.
I tried setting GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of service account's credential file. But, the plugin does not use this environment variable.
I know, it might be a problem with the plugin. But, I am wondering is there any way to set application-default-credentials.json using google service account.
format of application-default-credentials.json:
{
"client_id": "76....408.apps.googleusercontent.com",
"client_secret": "d-....D0Ty",
"refresh_token": "1/r............................emnY02",
"type": "authorized_user"
}
Service account's key format:
{
"type": "service_account",
"project_id": "ID",
"private_key_id": "9a4.................................bbaad80",
"private_key": "-----BEGIN PRIVATE KEY-----\nMI................................e\n-----END PRIVATE KEY-----\n",
"client_email": "name#project.iam.gserviceaccount.com",
"client_id": "10..................886",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/name%40project.iam.gserviceaccount.com"
}
I know, it might be a problem with the plugin. But, I am wondering is
there any way to set application-default-credentials.json using google
service account.
The answer is no. See below for details.
What you are calling application default credentials is actually OAuth Client Secrets. These credentials are used to authenticate (login) by a human to Google Accounts to generate OAuth tokens. You cannot use this type of credential file with GOOGLE_APPLICATION_CREDENTIALS.
Application Default Credentials (ADC) is not a credential, but a strategy to locate credentials.
A Service Account JSON file is used by a computer/machine to authenticate with Google Accounts and generate an OAuth Access Token (and optionally an OIDC Client ID token).
The two types of authentication result in similar types of tokens but cannot be interchanged without using different types of code and integration with the Google authentication systems.
The key point is that one requires a human to interact with Google, the other interacts silently with Google.

Cannot test Cognito authenticated API Gateway call in Postman (its an ADMIN_NO_SRP_AUTH pool)

I've managed to successfull login to the API gateway I've made via my iOS device and Cognito. The problem is I'd like to use postman to test the API calls then implement them on the phone. Currently, Postman cannot authenticate (despite AWS saying it can). No matter what I do I get a 401 error (visible in the screen-shots)
What I've tried
Downloaded the postman collection from AWS Api Gateway
Then imported it into postman, and switch the authentication to "AWS Signature"
And Here is a screen shot of the Postman Generated Header Info
If I understand correctly, you are trying to call an API Gateway endpoint that is behind the built-in Cognito Authoriser.
I think you've misunderstood how you call an Cognito Authorised API Gateway:
Authorise against Cognito to get an id_token
Call API Gateway with the Authorization header set to id_token
Renew id_token every hour
By enabling ADMIN_NO_SRP_AUTH you're allowing the first step (sign-in to Cognito) to be simplified so that you can more easily do it manually. (If you hadn't, then you would need to do SRP calculations).
One way to get the id_token is to use the aws cli (further ways are shown in the documentation):
aws cognito-idp admin-initiate-auth --user-pool-id='[USER_POOL_ID]' --client-id='[CLIENT_ID]' --auth-flow=ADMIN_NO_SRP_AUTH --auth-parameters="USERNAME=[USERNAME],PASSWORD=[PASSWORD]"
You can then use the result (AuthenticationResult.IdToken) as the Authorization header in Postman (no need for the AWS v4 signature- that is only for IAM authentication).
n.b. a much fuller explanation with images can be found here.
Here is what I finally did to fix postman auth issues
1) Turned off App Client Secret in the Cognito pool.
2) Ran aws --region us-east-1 cognito-idp admin-initiate-auth --cli-input-json file://gettoken.json
JSON file example
{
"UserPoolId": "us-east-1_**********",
"ClientId": "******************",
"AuthFlow": "ADMIN_NO_SRP_AUTH",
"AuthParameters": {
"USERNAME": "*********",
"PASSWORD": "***********"
}
}
3) Went to Postman > Authorization > Bearer Copied the idToken value into the token field and everything worked.
NOTE: For those wondering if not using a secret client key is safe. See this article.

AWS Cognito Post Authentication Lambda Trigger - groupConfiguration

Is it possible, via a post-authentication lambda to alter the list of groups exposed by the AWS Cognito Identity token?
The documentation for the post-authenticaion Lambda states the following:
"....
groupConfiguration structure – contains group-related information that can override group-related claims in the identity token."
Full docs: http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-post-auth
The AWS Cognito Identity token exposes the current payload:
{
sub: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
cognito:groups: [
"group1",
"group2"
],
iss: "https://cognito-idp.*****/**-****-1_********",
cognito:username: "Google_*****************",
.....
}
What I would like to to, via a post-authentication lambda is to alter the list of cognito-groups.
Any suggestions on how to do this?
There is a mixup in the documentation. This is not currently supported. We are actively working to fix it.