Using AWS Amplify authenticated user to communicate with an ALB or API Gateway? - amazon-web-services

I set up my AWS Cognito integration into my React Native app using amplify add auth according to the guide, all is well and good, I'm able to register and login in the app. The cli wizard associates two app clients with the User Pool it creates: [poolid]_app_client and [poolid]_app_clientWeb.
I would like to have authenticated users be able to communicate with a web app hosted on an EC2 instance. I thought I could use an Application Load Balancer to do this by setting it up to forward authenticated requests to the EC2 instance. Problem is, I'm unable to create an Application Load Balancer default action that authenticates with the Cognito User Pool.
If I choose the App Client associated with the [poolid]_app_clientWeb, I get an error on save: Error creating listener The user pool client must have a client secret. This is the client ID exported by the amplify tools to my React Native app in aws-exports.js.
If I choose the App Client associated with the [poolid]_app_client I get Error creating listener OAuth flows must be enabled in the user pool client.
Not sure how to proceed. Is ALB the way to go or API Gateway?

You should have made appropriate changes in "User Pools -> App Integration -> App client" settings for your client

API Gateway makes this much more straightforward. After I went through Create API, I was able to create an Authorizer that connected with my Cognito User Pool (the clientWeb one). Then, after creating endpoint Resources, I associated them with the authorizer in the Method Request section of their configuration.
I could then send the identity token I get from Amplify:
(await Auth.currentSession()).idToken.jwtToken
as an HTTP header value to the endpoints I configured.

Related

What is the best way to authorize an AWS API call for a logged in user?

I have a spring boot based web application which already authenticates the user. I would like to create some AWS APIs using AWS api gateway and a springboot rest app deployed on EC2. The user will log into the existing application and call the new AWS APIs from the browser ajax calls (like an SPA I guess but I have a server and can use client credentials/secrets if needed). What is the best way to handle security for the APIs. My first thought was to generate a JWT using a shared server side secret for hash and verify it with an AWS lambda. But this seems a bit non standard. Oauth2 might be better but might also be over kill. Not sure the performance would be good. Few requirements
token passed to the API should be a user specific token and have an expiration (and hence a refresh token)
The user is already logged into my web app and calling the api should not issue a login challenge.
AWS API Gateway should be able to verify the token before passing it to the application
Any token passed to the API should probably be generated on the logged in web application. Server knows the user is authenticated and should generate the user access token on behalf of the user. The AWS api should be able to figure out what privileges the user has based on the user principle or scopes in the token
I've thought about using Cognito AWS but I dont want to require the users to preexist in a user pool. Cognito seems geared more for the authentication rather than authorization and I would not be using the cognito login functionality. I dont know if its possible to use the oauth2/token endpoint alone with cognito.

Use one application login to access another application built using AWS (both on same domain)

I am working on a web application part of which is running on our local server and part of the application is implemented using AWS. I am looking for a solution where if the user logs in to the using the part of application that is running on local side, the authentication and authorization is carried over to AWS and vice-versa.
Check out AWS Cognito, specially User/Identity Pools. You can do SSO and pass tokens from one app to another and authenticate against the Cognito endpoint in AWS.

Where should be code for for getting Cognito token (frontend side or backend side)

I have application which has frontend code in angular. This frontend application calls backend APIs(spring-boot).
I have deployed this in EKS behind Application Load Balancer(ALB)
Request flow:
Route53 -> ALB -> Frontend Target Group or Backend Target Group.
I want to setup AWS Cognito at ALB for user authentication. I am going to federate user pool from my active directory. I want to allow only those users to login into website with username/password. I want to make sure backend APIs can only be called with valid login/token.
Questions:
What grant type should be used? (Authorization code grant/implicit grant/client credentials)
Where should I have code to get token from cognito? In frontend(angular) or backend?
Do I need to secure backend APIs, like APIs can be called with token only?
Or
Just securing angular route is enough? (because backend points are not visible from outside of cluster, they can be called only from frontend PODs)
For example,
We can keep mywebsite/login allowed without token,
any other pages (mywebsite/serach, mywebsite/home, mywebsite/product) allowed only if token is presented
Your angular frontend should initiate the flow using authorization code grant. The Cognito Identity SDK has some useful helpers for this but you can use any OIDC client SDK such as AppAuth.

AWS cognito: Store user auth token in backend server

I am developing a react native mobile app and using server side API for managing user related data (backend). Currently I am using AWS cognito for supporting user signup/signin and all the user details are seems to be saved in AWS user pool.
I want to store auth token and user details on my server side, so that I can use this details to fetch user related data. So, I want the following approach to implement
Request:
Mobile App UI -> Server API (backend) -> AWS cognito
Response:
AWS cognito -> Server API (backend) -> Mobile App UI
Is this possible? If not what would be the best approach.
Quick Response
If you are running Springboot in an EC2 instance you can asign a role to that EC2 instance with enought permissions and get data directly from your server app as an Administrator, i mean, using the SDK you can call AWS API requests just with that role, so you can retrieve the user data for all your users.
Other options
I think AWs has some services that make it easy to have this approach.
You can use Amazon Cognito Identity Provider to get credentials for an user and directly in the app you can call for example dynamoDB queries (etc) or you can do AWS API Gateway requests that are executed if the requests have valid credentials, this way you can call Lambdas and make some proccesing. If you need more details you should send more info to know the target of your app and make a better recommendation. Regards,

sendMessage to SQS from Browser

I am building an SPA with Django REST as the backend. Right now I am using the standard Django authentication system and User models.
I would like the JS running on the SPA to be able to insert messages into an AWS SQS (i.e. sendMessage).
AWS has these doc on calling sendMessage from JS in the browser.
They also provide these docs on how to authenticate the user. My thought right now is to use Amazon Cognito. From the FAQ:
Q: What if I register and authenticate my own users?
Amazon Cognito can integrate with your existing identity system. With
a simple API call you can retrieve a Cognito ID for your end users
based on your own unique identifier for your users. Once you have
retrieved the Cognito ID and OpenID Token Cognito provides, you can
use the Cognito client SDK to access AWS resources and synchronize
user data.
Am I correct that for this to work, I would need to:
Create an IAM user for each user in my system. Or do I just need one IAM role?
When the user logins in my site (Django backend), I would have my backend then make "a simple API call [to] retrieve a Cognito ID"
Send that Cognito ID when the user loads the SPA.
User the Cognito ID from the JS running in the browser to call sendMessage to the SQS queue
Am I missing something here? Is there someway to remove the Django User backend and just user IAM Users so that I can avoid having to keep the two users lists in sync? I found this project but it does not seem to be maintained.
UPDATE:
It seems that there might be an alternative method of doing this where I don't use Cognito at all but rather expose an endpoint that can sign requests, "Query Request Authentication". This Heroku page talks a little about building a signing service.
Is this in fact an alternative option and if so what are the pro/cons of these approaches?
Amazon Cognito does not require you to register IAM users, just the 2 IAM roles. A slight modification to what you would need to do:
Create an Amazon Cognito Identity pool, configure with your developer provider.
Update the IAM roles associated with your pool to allow access to the services you want (for instance SQS).
From your Django backend, call GetOpenIdTokenForDeveloperIdentity to get the OpenId Connect token and identity Id for this user, return this to your JS application.
Configure your CognitoCredentials in the JS SDK. In the logins map, use the key cognito-identity.amazonaws.com and the value as the token returned from your Django backend.
Use the JS SDK to call SQS or any other services you wish from your application.
While using pre-signed URLs for SQS can work, using Cognito with the JS SDK will allow you to leverage other services supported by the SDK (DynamoDB, SNS, S3, etc).