I'm building a web app that has a React frontend and a Go backend; I'd like to build out the backend to call services and do other things instead of just having a front-end based app. To my understanding from some other posts, the authentication flow should be as follows:
Client inputs username and password
Frontend calls AWS Cognito user pool to verify credentials. If correct, JWT tokens are sent back to frontend.
The frontend sends these tokens to the backend
The backend verifies the tokens and checks the access token is valid.
If valid, the backend then uses the ID token for other services.
Is this correct? If so, then I'll need a Javascript + Go Cognito SDK?
Furthermore, it seems AWS has Cognito support for Amplify but I don't see docs for just Javascript or Go. I did find functions in the Javascript and Go SDK, though; however, I couldn't find examples how to use them properly. Would anyone know of a good resource?
Related
I am currently working on building a mobile app which will require the users be authenticated, and have them specific privileges on what they can do (for example, a logged in user will only be able to manage some of their data held in the backend database).
I think I do understand the differences between ID token (user identity) and Access token (for authorizing between the mobile phone client and the back-end), but I am not sure what I intend to do conforms to the best practices regarding authentication and authorization.
Let me summarize what I am planning to do:
front end will be a Flutter/Dart mobile app
authentication will be done through Google Firebase Authentication service
my back end will be hosted in AWS:
API Gateway will serve a unique graphQL endpoint
API Gateway has an associated Lambda authorizer function which processes requests prior to the actual "application" Lambda functions
"application" Lambda function serves GraphQL requests (using python ariadne library), including authorization business logic
Database is a managed PostGreSQL inside AWS
The authentication / authorization workflow is as follow:
Not all of this has been implemented yet, but on the paper I think it could work.
However, it goes against several good practices regarding token usage:
the ID token is sent along an API call which is advised against (see this nice auth0 blog post)
I make no usage of access token between the front end and the back-end (could the AWS policy generated at step 5 fullfill this role?)
I do not leverage the audience claims in tokens
Note: as GraphQL exposes a single endpoint, I am not sure of what the content of the access token should be
I am new to Authentication / Authorization and would gladly have some insight regarding the best way to actually make everything work as per best practices, accounting to the following contraints:
authentication is outside of AWS
the APIs are GraphQL
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.
The client seems to generate tokens in a way I cannot replicate in Jmeter. The app is not using SSO, or Google authentication. Just username/password
The Authentication flow would be similar in Postman, except Postman has an option for AWS user pools and Jmeter does not (just mentioning this in case anyone has done it manually in Postman).
I've tried everything I know of, I'm on my last straw and I can't believe apparently nobody load tests Cognito apps!
Looking into Amazon Cognito User Pools Auth API Reference - it's normal OAuth so you need to start with AUTHORIZATION endpoint and once you get the key proceed to TOKEN endpoint.
Alternatively you can use AWS SDK for Java from the JSR223 Test Elements.
Check out How to Run Performance Tests on OAuth Secured Apps with JMeter article for more information on bypassing OAuth login challenge in JMeter tests
I am trying to set up AWS API gateway in our env. I have created an api gateway with a resource and a cognito user pool for authentication. I created an app client in cognito and able to add users. But I am not clear on invoking the sign in page when accessing the endpoint using api gateway. Right now i am passing the JWT token in the Authorization header manually for testing purpose but in realtime, when I hit the api gateway endpoint i want to redirect to the signup/sign-in page programmatically add the auth header once the user authenticated.
Could you please help me understand what I am missing here?
An API is a backend service usually called through front end app or other backend service. An API should not assume the caller is a human using a front end, and should not assume the front end is a web app, it might be a mobile application, a watch app, a TV app etc ...
That being said, your API should not redirect to the user authentication page.
The normal workflow would be
Customers connect to you web page
Code on web page checks if the user is authenticated
When user is not authenticated, web page redirects to authentication system.
After authentication, authentication system redirects back to your web page
Web page collects token generated by authentication system
Web page call API, including token in header / query strings.
You can substitute web app here by mobile app or other type of front end.
Check an example here. https://github.com/dabit3/stockholm-loft-react-native
This is a React App, using Amplify it demonstrates how the app itself is managing the redirection to the authentication page and how it pass authentication token to the API. The example is using GraphQL API, but you can do something similar with REST API.
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.