AWS API Gateway authorizer google sign in - amazon-web-services

I have an API Gateway/lambda REST API that is being accessed from a react web app. I need to add authentication using google as an identity provider. The app should also keep the user signed in.
I understand when the user first grants access to the (react) client app, it should send the ID token to my backend, which should then verify the token.
Since my architecture is serverless, I assume the verifying should be done in the API Gateway authorizer function, which then grants access to the API on successful verification of the token.
My question is, how do I then create a persistent session? Should I be saving anything to my database about the user? Does the token need to be verified on every API call?
Should the authorizer be checking if the user is already registered or if it's a new user?

It would be easiest to use AWS Cognito for this. Configure a user pool as an authorizer for your API gateway and then configure Google as an identity provider for that user pool. This link might be helpful: https://docs.aws.amazon.com/cognito/latest/developerguide/google.html. Cognito even has a hosted UI if you want to use it for signing users in.
As for your question about persisting user sessions, they usually get persisted in local storage in the browser or in a cookie or some similar mechanism. You can also persist them on the server-side in a database like you were mentioning but that isn't really for authentication purposes.
The user session will contain an access token. The access token is short-lived, meaning you can only use them for an hour usually. After that you have to use a separate refresh token to generate a new access token. And to be extra safe the refresh token itself will expires after a few days (and you have to sign back in).

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.

User Management and Token based authentication in AWS Cognito and AWS API Gateway

I am running a simple Rest API based on FastAPI. This API runs in a AWS Lambda container. I have added API Gateway as a trigger.
Now I want to secure this API.
My expectation:
I create a User and a Password manually
The user can call a specific endpoint with his User and Password to receive an access token
With this access token the user should be able to access the API e.g. by passing a Bearer Token.
Actually I have tried AWS Cognito, but the only way to receive an access token is to use the CLIENT_ID and the CLIENT_SECRET. And I don't want to share this to external users of the API.
I think this CLIENT_ID and CLIENT_SECRET is made for a web-app or sth. like that but this is not what I want. I just need a simple pipeline of: user creation -> user login -> Access_token -> API.
I hope anyone of you is able to share a guide or similar. Maybe AWS Cognito is not made for such a use case , if you think so then just let me know and why.
Thanks in advance.
yes, absolutely it's possible, please refer below image.
In the first step your app user signs in through a user pool and
receives user pool tokens after a successful authentication.
Next, your app exchanges the user pool tokens for AWS credentials
through an identity pool.
Finally, your app user can then use those AWS credentials to access
other AWS services such as Amazon S3 or DynamoDB.
later on you need some custom authorizer in API-Gateway (lambda) to validate the token.

AWS Cognito with google provider, how to handle the response from google?

So I'm using cognito User Pools with Google as an Identity provider. I configured everything and I'm sending the data to google, which redirects back to the amazon auth endpoint, which then redirects back to my app with the following parameters in the URL:
AccessToken
ExpiresIn
IdToken
TokenType
Now, I have no idea how to use these to actually create a Cognito "session" that goes into the javascript api workflow and just becomes automatic (sending, receiving and renewing the token)
How do I achieve this?
Using IDToken to Authenticate Your API
After you authenticate, you can cache the IDToken in Browser and use it when the logged in user requests for API Calls from your web or mobile application. Then you can validate the token at your API endpoints for each request.
Validating IDToken
For more information about using the tokens and validating it at API endpoints, refer AWS documentation on Using Tokens with User Pools. There is a new library introduced by AWS called aws-amplify which simplify some of the implementations. If you are using AWS API Gateway for your API, you can use a custom authorizer Lambda function to do the validation.
Storing the IDToken and Security
In addition, the IDToken is a stateless token, which means it doesn't have a session in connection with AWS Cognito Once issued. Which means you cannot revoke it after issuing. Therefore it's important to keep its expiry short.
To allow your authentication API to issue new IDTokens before it gets expired, you might need to store the Refresh Token in your backend and use it to issue new tokens before the IDToken expires to implement a sliding window.
Note: Storing the IDToken in browser, you can decide in using multiple storage options available (E.g; Cookies, LocalStorage). However, I'm not going to comment on the security implications since it is itself a long discussion where there are still opinionated areas. The standard approach currently available, is to set up a serverside Cookie and implement CSRF. It will be challenging to implement unless you use the IDToken just to initiate the authentication and use a session instead, for the recurring requests.

Amazon cognito not giving refresh token provided by federated identity provider (Google login)

I am trying to add a Google login through Amazon Cognito, I have setup everything needed, I have also configured the attribute mapping from google to my pool attributes, I've mapped 'access_token' attribute to 'google_access_token' attribute and 'refresh_token' to 'google_refresh_token'. When sign in process starts, google prompts me for required permissions needed and redirects back to my app, and I can see on cognito dashboard that user is added with access token mapped in 'google_access_token' but no refresh token there. I double checked every configuration everything seems fine. I also tried mapping other attributes like 'token_type' and 'expires_in' those are getting mapped except the refresh token.
I found out that for generating refresh token from google, client need to pass 'access_type=offline' parameter in the GET parameters which Amazon Cognito DOESNOT send while starting OAUTH login with google, so google doesnt provide google refresh token. So in nutshell there is no way ( Atleast now ) to get refresh token from google and access google APIs "offline" if you are using Amazon cognito. Alternatively I used Auth0 which supports this and can send access_type parameter to google and can store refresh token.
If I may ask, have you seen this document?
Understanding Amazon Cognito user ool oauth 2.0 grants
To get to the point, this concern may be because of the OAuth Flow we have set in the Cognito User Pool. We need to use "Authorization Code Grant" as the OAuth flow. Implicit Grant doesn't generate refresh tokens, but Authorization Code Grant does.
If you're using Amplify framework in your project, this framework will do most of the heavy lifting for you. You just need to setup the User Pool's app client correctly and configure Amplify for that specific app client.
I hope this helps.

AWS Cognito federated identities + permanent access key for programmatic API

I have an API service, which I'm going to deploy using AWS API Gateway with Cognito authorizer + Lambda as backend. This service will be used by our javascript client. Also, it should be exposed to end users as raw endpoints for programmatic access.
While it was quite easy to enable signup/login in js client using federated identities, I can't figure out the way to provide users with private access token to include directly in http headers.
Here are two authentication flows, I'd like to get in the end:
The flow for js client user:
User signs up with Facebook or Google.
User verifies his identity.
After login, user goes to the Profile/API Keys section in the interface.
User copies access token and can include it in http request header in any http client (httpie, curl, language libraries whatever)
The flow for admin created user:
Admin creates user.
Access token is generated for that user.
Admin passes generated access token the user.
User can include it in http headers to make request, as in previous flow.
An access token should be permanent, and can be regenerated by user at any time (think of Stripe API access keys).
The point here is to eliminate additional steps for the user to start using service programmatically. The closest thing in AWS docs so far is developer-authenticated-identities, but user should utilize AWS sdk anyway.
One possible way to accomplish this task is to use Custom authorizer instead of Cognito authorizer in API Gateway. Custom authorizer could implement logic based on e.g. auth header name and decide to either authorize in Cognito or to user API access token in database. I'm not sure, if it is possible, and if it is the major drawback is to reimplement Cognito authentication flow in lambda function.
The question is how can I accomplish such API access token (re)generation using Cognito or API Gateway?
The first flow should be possible with User Pools. Cognito User Pools now has a federation feature where you can federate using Facebook/Google and receive access token/refresh token depending on the flow used.
For admin created user, the user would need to authenticate before tokens are issued but this can be achieved by creating the user with a temporary password and signing the user in with that password, after which it can be changed and logged in again to receive access/refresh token.
The refresh token use case is that it can be used against the Cognito APIs to receive a new access token. When the refresh token expires (default is 30 days but it is configurable), the user would have to authenticate again.