How can I use Cognito OAuth 2.0 to authenticate a API Gateway request without having an app client secret? - amazon-web-services

I'm using aws sdk to manage logins and signups on my app and the sdk requires my app client to have no secret key. This is a problem since I intend to use Cognito to authenticate the API gateway. I tried to enable OAuth 2.0 client credentials flow on app client settings, select a scope and give it to the API method, but when I try to save the app client settings I get:
"We were unable to update your App Configuration: client_credentials flow can not be selected if client does not have a client secret. (Service: AWSCognitoIdentityProviderService; Status Code: 400; Error Code: InvalidOAuthFlowException"
Is there a better way to configure API Gateway with Cognito? Am I doing something wrong?

You need to create a new app client for your API with a secret.
front end client - app client with out secret
Backend client / api - app client with secret
Client credentials is a usually a method for service-service authentication. You have to store the secret securely.therefore insecure to use in an unsafe front end app such as an html website.
Hope this helps.

To add to Arun's answer, the API should not need a Cognito OAuth client entry and just needs to validate received Cognito access tokens.
Typically this is done by downloading JWKS keys from Cognito - and API Gateway has a setting that automatically does this.
I can provide further details if you run into problems identifying the user after token validation.

Related

AWS API Gateway Authorizer does not authorize non-default Cognito User Pool App client tokens

I have created a new app client in Cognito, the tokens from the default app client are marked as valid by the API Gateway but not the token from the new App Client.
The API Gateway responds with HTTP 401 - UnAuthorized.
This should work because both the app clients have full permissions to the underlying users stored in Cognito.
I couldn't find any relevant documents explaining this discrepancy.
So, I was linking my AWS User pool to Amazon Alexa Smart Home Skill using this blog https://aws.amazon.com/blogs/compute/amazon-cognito-for-alexa-skills-user-management/.
On successfully linking the skill, Alexa would only send the accessToken in the subsequent API's.
The AWS API Gateway authorizers only check for the ID token and will deem the request invalid if it is given an AccessToken.
Thus, the requests were failing. It has nothing to do with default or non-default app clients.
Using a Cognito custom authorizer seems the best option, will disable API Gateway authorization.

What the settings mean in AWS Cognito User Pool App Client

I searched all over, tutorials, web, everybody jumps away without explaining(I understand why) the checkboxes in app client settings:
Enable sign-in API for server-based authentication
Only allow Custom Authentication
Enable username-password (non-SRP) flow for app-based authentication
The learn more link does not help me, lots of information and not so easy to understand, grasp. Can someone explain this settings?
Here is my take on the matter.
App client has several Auth Flow Configurations.
1. Enable username password auth for admin APIs for authentication (ALLOW_ADMIN_USER_PASSWORD_AUTH)
This enables Server-Side Authentication Flow. If you don't have an end-user app, but instead you're using a secure back end or server-side app.
2. Enable lambda trigger-based custom authentication (ALLOW_CUSTOM_AUTH)
This enables the Custom Authentication Flow. This can help you create a challenge/response-based authentication model using AWS Lambda triggers.
https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html
Under User Pools -> Triggers you can see many lambda functions. You can use Create Auth Challenge, Define Auth Challenge and Verify Auth Challenge Response functions to create a custom authentication flow.
3. Enable username password based authentication (ALLOW_USER_PASSWORD_AUTH)
This enables Client Side Authentication Flow that uses user password-based authentication. In this flow, Cognito receives the password in the request.
You can use AWS Mobile SDK for Android, AWS Mobile SDK for iOS, or AWS SDK for JavaScript to implement this.
4. Enable SRP (secure remote password) protocol based authentication (ALLOW_USER_SRP_AUTH)
This is similar to the above flow in section 3. except for the password verification. This flow uses the SRP protocol to verify passwords.
http://srp.stanford.edu/whatisit.html
https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UserPoolClientType.html
5. Enable refresh token based authentication (ALLOW_REFRESH_TOKEN_AUTH)
After successful authentication, Amazon Cognito returns user pool tokens(Three tokens) to your app. You can use the tokens to grant your users access to your own server-side resources, or to the Amazon API Gateway. Or, you can exchange them for temporary AWS credentials to access other AWS services.
The three tokens are ID Token(JWT), Access Token, Refresh Token. The refresh token can be used to retrieve new ID and access tokens. Once you login to a mobile app, you are not needed to log in each time when you close and open the application and this functionality is implemented using refresh tokens.
https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html
What about Amazon Cognito hosted UI ?
App clients can be configured to use built-in Cognito webpages for signing up and signing in users. When using the hosted UI you can enable both the Authorization code grant and the Implicit code grant, and then use each grant as needed.
https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-app-idp-settings.html
Here is my attempt at explaining these options. Before that I would like to briefly mention about Oauth2, which is the protocol on which AWS Cognito is based.
In the context of AWS Cognito, Cognito itself is the Authentication (OAuth) server and also the Resource server (because we create users in Cognito user pool) and your app would be the Client (which sends the authentication request). The client has to first register itself with the OAuth server - this is what is being done in the "App clients" section of Cognito.
The recommended OAuth2 flow is Authorization Code Grant flow. In this flow,
i) The Client sends username/password to the OAuth Server.
ii) The OAuth server validates and calls back the client with a
authorization code.
iii) The Client again sends this code back to the OAuth server
iv) The OAuth server sends the tokens to the Client.
Please read the above linked article for more explanation on OAuth2.
Now explaining the options in Cognito App Client settings:
1. Enable sign-in API for server-based authentication
With this option, your client app can directly receive the tokens without having the additional step of first getting the authorization code.
There are Cognito APIs like AdminInitiateAuth, Admin-* which does this. However, these APIs require AWS admin credentials. Hence usually these calls are done by the backend server of the client app. The front-end can pass the username/password to the backend and the backend server can communicate with AWS Cognito and authorize the user.
2. Only allow Custom Authentication
Here you don't use the OAuth provided authorization code grant flow. Instead, you can define your own steps and challenges. Your client app can ask a secret question etc, before authenticating and giving tokens.
3. Enable username-password (non-SRP) flow for app-based authentication
This is the least safe flow. This skips the part of returning the authorization code and directly returns the tokens back to the client.
I hope this explains.

AWS Cognito UserPool Authentication on HTTP Request

I'm building an API using the serverless framework. I'm trying to authenticate requests coming in through API Gateway by leveraging Cognito (UserPools), and giving each of my users their own authorization token for each API call they make.
Trying to test it with postman I'm not able to make a call and pass authorization. I've tried setting Authorization in the header with the App Client Secret, but I'm just getting "Unauthorized" back. Is there something I'm missing?
You should be using the token rather than the App Client Secret. How are you retrieving the token?
For user sign in authorization, you must be sure you uncheck the option to generate client secret when you are creating a new Client Application inside UserPool.
In your API Gateway you create an authorizer making a reference to you before created UserPool. Inform "authorization" for the header.
Using a AWS third party SDK service (or just their API), signin with a valid user. You will get 2 types of tokens after the login, make sure you keep the right one. I advise you to check the token through the API Gateway authorizer testing option. Note: This step is the most important, as you are isolating the token you get and the authorization service. This way you can track the source of your problem.

Use the token response from SAML authentication with User Pools to retrieve AWS Temporary Access keys

How do I use the token response from SAML authentication with User Pools to retrieve AWS Temporary Access keys and Make API Gateway Calls?
I have configured a Cognito User Pool with an associated App client. I have configured Okta as a 3rd Party SAML Identity provider. Using the Amazon hosted login https://[cognito domain name]/login?response_type=token&client_id=[your App client id]&redirect_uri=[your App client redirect URL] I am able to be redirected to my ReactJS application with the #access_token in the header.
I am trying to now user the #access_token to call API gateway. I have been following this guide as well as aws-amplify. To my understanding I need to use the #access_token to get AWS access keys to make the call to API gateway.
I am trying to do this with the following code:
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:xxxxxxx-xxxx-xxxx-xxxx-xxxxxx',
Logins: {
'cognito-idp.us-east-1.amazonaws.com/us-east-1_xxxxxx': #access_token
}
});
but not sure how this integrates with aws-amplify, and I have not successfully retrieved AWS temporary access keys to make API Gateway calls.
I previously had this working using users in the Cognito User Pool but now I need to include Okta as an identity provider.
I found I needed the #id_token rather than the #access_token to accomplish what I was trying to do. I enabled the #id_token by selecting the following options in my Cognito Pool App Client Settings:
I was then able to follow Cognito hosted UI.

How to Verify AWS Cognito user on Server (running on nodeJS)

I am using AWS Cognito User Pools to signup & signin my users(client, iOS). My user's make calls to endpoints on the server running on NodeJS (EC2 Instance). How can I authenticate my users on the server (NodeJS) ?
One way that I see is, to generate a JWT token on the client side and pass it to the server along with the POST request and have it verified.
Is this possible using Cognito Userpools ? or Is there any better alternative ?
First of all AWS Cognito Userpools is able to generate the JWT token(id_token) once authenticated against the Userpool.
There are two ways to generate the JWT token.
Using AWS Cognito Userpools Hosted UI you can can get the id_token. If you enable openid claim and use the implicit grant it will directly redirected to your defined URL from Cognito Login Page. If you use authorization code flow, you need to use backend code with AWS SDK and token endpoint.
You can also use the AWS SDK and implement your custom login page where it generates the id_token using the SDK.
The id_token can be verified at your API using a standard JWT verification library.