Exposing Cognito Protected AWSGateway APIs to clients - rest

Use-case:
We have a few AWSGateway APIs which our clients can use to do somethings in the backend. These APIs are Cognito protected. Currently our clients are using this APIS through an android app which was built using Cognito Mobile SDKs.
Now we are trying to expose these APIs to our clients to be integrated into their internal workflows.
I was trying to find what is the best way to do this. Currently I am not able to find any resources on how to do this.
I have seem the server side user of AWS Cognito but I don't think that is what we want to do here.
Thanks.

To answer your question correctly we need more information.
Can the internal workflows be configured to use REST Services?
What authentication processes does the internal workflows support?
SDK or no SDK
You can access the webservices in API Gateway via a generated SDK or your own code.
Instructions to generate an SDK from the API Gateway Console are found here.
To invoke the webservice with authentication can be done in four ways IAM, API Keys, Cognito, custom authoriser. I am going to mention the first three.
IAM
Step 1, create a user in IAM with an access key and secret key.
Step 2, is too setup a role to access the API using IAM. Go to
IAM, select roles, create a role, and grant it access to your
API Gateway functions. Which would look something like this:
Sample IAM Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::account-id:user/Alice",
"account-id"
]
},
"Action": "execute-api:Invoke",
"Resource": [
"arn:aws:execute-api:region:account-id:api-id/stage/GET/pets"
]
}
]
}
allocate this role to the user you created. Policy examples are available here.. For more authentication options that include local certificates etc look here.
Step 3, call the API using the AWS Secret and Key SDK.
API Keys
If you add keys to your APIs the mobile app will fail as it does not have these keys. It would be best to deploy a different version of your APIs that could wrap the existing ones, could provide additional functionality specific to the workflow. To find out how to do this follow this link.
The advantage of API keys are that you can throttle access to your API Gateway functions, remove the keys at will, recycle them etc.
Cognito - Federated Users
Your mobile users are actually authenticating using federated users. However, one of the federated user channels happens to be cognito. You can add more, OpenAuth, Google, Facebook, SAML, etc, here you could add the Authentication type used by your client. A user would then use their username and password, to authenticate to the clients security provider, those credentials are then passed through to the API via federated users, and therefore federated users must be setup to use the same authentication mechanism as your client. See the following blog post
For this solution we have multiple options. 1. Pass the user credentials through to the API with federated users, this assumes the users interface calls the webservice but as you mentioned it is workflow, and I assume the user does not access the service directly as they do with the mobile application. i.e. services are called by a machine as a background process on a server. Which means this solution will not work. Option 2. is to create a new user, in cognito for the client. This is the same as accessing the service via the mobile app. To do this needs a little work extra work on the client as you need to retrieve the temporary access tokens.
Step 1. Use the SDK, or code the interface to the API on your own.
Step 2. Generate a user in Cognito for the backend system to use.
Step 3. Use the cognito user to obtain access tokens
Step 4. Use the access tokens to access the webservice in API
gateway.
Suggested solution
Create a second version of your API as a wrapper or extension to your mobile API and use API Keys as described above. Why?
Can throttle access to the APIs
A different version means you can extend it and add additional functionality specific to workflow
Easiest to implement as there is no key exchange, such updates to
the request header.
EDIT: My suggestion of solution 2 is incorrect. AWS Documentation says the following To include API methods in a usage plan, you must configure individual API methods to require an API key. For user authentication and authorization, don't use API keys. Use an IAM role, a Lambda authorizer, or an Amazon Cognito user pool.
AWS Also says the following is available for controlled access
Resource policies let you create resource-based policies to allow or deny access to your APIs and methods from specified source IP
addresses or VPC endpoints.
Standard AWS IAM roles and policies offer flexible and robust access controls that can be applied to an entire API or individual
methods.
Cross-origin resource sharing (CORS) lets you control how your API responds to cross-domain resource requests.
Lambda authorizers are Lambda functions that control access to your API methods using bearer token authentication as well as
information described by headers, paths, query strings, stage
variables, or context variables request parameters.
Amazon Cognito user pools let you create customizable authentication and authorization solutions.
Client-side SSL certificates can be used to verify that HTTP requests to your backend system are from API Gateway.
Usage plans let you provide API keys to your customers — and then track and limit usage of your API stages and methods for each API
key.
Not all the approaches above are intended for authorisation, for example CORS actually protects the user from cross site scripting, and as seen API Keys are only for usage plans. Resource policies just further secure the API by limiting access to IP Addresses, thus your only options really are IAM Roles as described in option 1, and federated users as described in option 3 or your own custom lambda authorize, if you are using Lambda, or your own authorizer if you are using something other than lambda wrapped with API Gateway.

I guess it will be service to service or (Server to Server) communication, for this terminology used is Oauth Standard is client_credentials grant type.
Please refer the documentation for getting token
Once the token is acquired, you need to pass this token either Authorization or API Gateway Custom Header for AWS Cognito.

You can use API Tokens alone for authorization (unless this has been removed recently)
I have used them on multiple applications.
This is not recommended for Authentication -- but it is application specific if they are sufficient for authorization
They have been supplemented by more secure methods at the expense of significant complication for both client and server.
API Tokens have the advantage of ease of use for issuer, client and server as they do not require complex signing or protocols -- however they are not as fundamentally secure as they may be reused and generally do not expire as quickly. Otherwise they are equivalent to bearer tokens.
Security is very context dependant -- consider these question:
what exactly are you protecting against (providing security for) ? What is the risk and cost of a security breach ? What is the cost/effort to implement and use it?
Many security 'holes' are not in the authentication protocol handling itself but rather in how data is managed 'outside the box' -- No security is perfect, meaning aiming for perfect security has unbounded cost with decreasing effectiveness. Generally, it is recommended to balance the risk and cost of potential loss vs cost to implement and maintain.
You can have a 'highly secure' API but also have a high risk of breach and data loss due to handling before and after passing through the protected gateway. There are many reasonable cases where instead of focusing on securing the 'front door' with bank vaults and armoured trucks, instead securing the data handling such that no data that is a significant security risk passes through the front door.
AWS Provides a range of technical features -- but it is ultimately up to each customer to implement them appropriate for their use. API Keys do have a range of appropriate use cases, particularly in server-to-server communications, especially where personal identity (and PI data) is not involved, or where the API involves mainly services instead of data (e.g say a image thumbnail API that stores no state and provides no access to data). When backed by use of HTTPS/SSL and possibly other security factors such as account passphrases, IP range whitelists, and a general policy of least-access.
Don't underestimate the "Sticky Note" factor. If you make secure access too painful to your users they will find a way to make it less painful, but less secure then simpler measures which they would not have had an incentive to circumvent.

Related

Is it possible to have two type of auth flow?

Background information: The REST API will be used by a web application and server
We are thinking to have the code flow for the web application and client credential flow for the server part (machine to machine authentication). As tool, we will be using keycloak
But the problem is now that we are not sure if it is possible to have two oauth flow on one REST API.
Is it possible to have two oauth flow for one REST API?
And if it's possible, how can you do it?
This is fine. In both cases the clients will perform OAuth flows using Keycloak, and these can be completely different. Your API needs to knows nothing about how clients authenticated, and in both cases receives a JWT access token.
The two different clients will not always call the same API endpoints. They are likely to use different scopes and claims, and your API authorization design needs to deal with this. The server client will not provide a user identity via a subject claim, whereas the web app will.
The way to cope with these differences is usually to design a ClaimsPrincipal during JWT processing, then apply authorization rules based on the data received within the API's business logic.
In some cases, operations designed for the server client should not be callable from the web app, and vice versa. Scopes and claims will enable you to achieve this.
EXAMPLE API
Maybe have a look at this code sample of mine and the blog post. The key point is that the API performs these steps. If you do the same steps you will be in good shape:
Validates JWT access tokens
Builds a claims principal
Enforces scopes for each operation
Uses the claims principal to apply business authorization rules
My API does some slightly advanced stuff like look up extra claims, which you can ignore. Note that the API doesn't know or care which flow clients used - there could be 5 different flows. The API's job is just to work with scopes and claims.

OAuth2 for REST API with tightly coupled SPA as only client

I'm developing a REST API with a tightly coupled SPA as the only client of the mentioned REST API.
Let's say the SPA is available at myservice.com and api is under myservice.com/api. They're basically one service, just split at code level, and deployed at different root paths.
What I'm using for security right now is OAuth2 with ROPC (username/password) grant type.
Here comes the problem. I keep reading everywhere that ROPC is not secure and should not be used. What should I use then?
My REST API acts as an authorization server but it doesn't have any web interface itself. So any flow involving redirect doesn't really make sense. The SPA and API are so tightly coupled that for an end user they're basically one application. There's no 3rd party.
I could add simple login form to the API available at let's say myservice.com/login. But I'm struggling to see the difference that would make.
Security in this application is very important.
Here are my questions:
Is using ROPC really dangerous in this scenario?
What would be the perfect way for authentication and authorization?
Or maybe OAuth2 is completely redundant without a third party?
Technologies used:
Server: Spring Boot
Is using ROPC really dangerous in this scenario?
No, not really providing:
a) You don't store a user's password - maybe only use it to get the initial access and refresh token - although that could be tricky with an SPA.
b) Your SPA client and the resource API are owned by you, so you don't need the user to consent to specific scoped access for the SPA.
What would be the perfect way for authentication and authorization?
It depends on lots of things. Not enough info to try to answer that. OAuth2.0 (with a probably implemented Authorisation server) is a pretty good way for the example you have here.
Or maybe OAuth2 is completely redundant without a third party?
If other applications will use your API in time then OAuth2.0 is probably a good call. Otherwise you could probably use a more simple solution e.g. session cookies as all sits on same domain.
Answer to this can be taken out from OAuth 2.0 specification (RFC6749) itself. It define when ROPC grant is suitable for,
4.3. Resource Owner Password Credentials Grant
The resource owner password credentials grant type is suitable in
cases where the resource owner has a trust relationship with the
client, such as the device operating system or a highly privileged
application. The authorization server should take special care when
enabling this grant type and only allow it when other flows are not
viabl.
According to your explanation, you have tight coupling with SPA and backend. Also you have both authorization server and resource server built as one. This is completely acceptable implementation.
The authorization server
may be the same server as the resource server or a separate entity.
So what matter now is to clear out why you use OAuth 2.0 in your scenario.
If you are using OAuth 2.0 to obtain tokens, maintain them as defined through OAuth 2.0 specification, then this is completely oaky. But if you are doing this to follow a trend, think twice.
OAuth 2.0 implementation comes with it's own complexity. You have to maintain user identities, maintain tokens and renew them. You are building a complete authorization server by yourself. But this also have some advantages as well.
For example, same authorization server can be used to issue token for future integrations/secondary app. IMO, usage of OAuth 2.0 make integrations easy as it define a protocol for issuing tokens, renew and revoke them.! But in such integration scenario, may be you will require to use a different grant. Still, your API being authorized on token, you only need to worry about how new integration/application obtain tokens. This is better than using authenticated sessions
Going back to your questions,
Q : Is using ROPC really dangerous in this scenario?
As explained, if there is a correct trust relationship between client and authorization server, then it is fine. But be mindful about complexity comes with having a authorization server.
Q : What would be the perfect way for authentication and authorization?
OAuth 2.0 is for authorization. You obtain access token and use them to authorize against your protected APIs. From APIs you do a token validation to detect correct access levels/permissions.
If you want authenticaiton, then you must use OpenID Connect. It is a protocol extended from OAuth 2.0. And allows your application to authenticate the end user based on ID Token. You can use ROPC grant to obtain an ID token.!
Q : Or maybe OAuth2 is completely redundant without a third party?
Not necessarily. It allows you to design your APIs in a modern, standard way. Who know what future hold (again the integration scenario). Following a protocol allows that easy.
Only advice, follow specifications closely. Do not invent your own protocol/adaptation. It makes things harder to maintain.

OpenID Connect User Mapping

Currently my organization uses a number of web apps/mobile apps/APIs, some of which authenticate against an in-house IdP and others which use a third-party proprietary system (over which we have no control).
We have been asked to implement SSO for these web applications and as a result I have been reading up on OpenID Connect. I believe this would be a better solution than SAML given that (a) end-users are not always enterprise users, and (b) SAML not designed for mobile applications.
I believe I understand the flow reasonably well but have one sticking point. To allow users to authenticate using an external IdP, we would need to map the user back to our internal id. For example, user authenticates using OIDC/Google, resulting in us receiving the user's unique Google idenitifer (and email etc if we queried further), but this is not useful to us until we can map the Google identifier back to our internal customer id.
Is this mapping out of scope for OIDC? If so, is there a best-practice method for doing this? I'm sure we are not alone in this requirement...
Thanks,
John
Is this mapping out of scope for OIDC?
Short answer, yes.! If your backend require a comparison/validation with internal identity details, then it has to be done out-of-scope of OpenID Connect(OIDC) protocol. OIDC simply define the process of obtaining tokens (ID and access token), which are required for authentication and authorization.
is there a best-practice method for doing this?
One option is to use out of band directory synchronization. For example, Google provider Google Cloud Directory Sync (GCDS), which allows you to synchronize identity details to LDAP or MS Active directory. Other alternative is to use SCIM protocol to communicate and provision users dynamically. For example Google provide that support as well.
Alternatively, you can use just-in-time provision at the time you receive tokens. This support will depend on your identity provider implementation. For example, WSO2 identity server support both JIT provisioning as well as SCIM.

Using Cognito for REST API authentication

I'm looking to use API Gateway + Lambda + Cognito User Pools to build a simple REST API.
The API will be used in two ways. The first is to support a basic web app (hosted on CloudFront + S3). Authentication for the web application uses the hosted Cognito sign in / sign up flow and is working fine (with API Gateway setup to use the user pool authenticator).
The second method will be for customers to use the REST API to communicate with the system.
As an example, the client might use the web app to configure a workflow and then use an API to invoke that workflow.
What is the recommended method of authenticating the API for use with backend services?
Traditionally, I'd expect to use an API key + secret token for this purpose. I have no issue creating API keys in the API Gateway interface however I can't see anyway to link that to a specific user, nor can I see any method of specifying a secret token alongside the API key.
And assuming the above is possible, how would I set it up in such a way that I could use the JWT-based approach for the web application and the API key + secret token for customers to use.
EDIT: Additionally, I notice that app clients have an ID and a secret. Are they intended to be used for 3rd API-based-authentication (similar to how other systems make you create an app for API access)? I'm a bit skeptical because there's a limit of 25 per user pool, although it is a soft limit...
I have been searching for an answer to this myself and my searching led me to your question. I will give you my best answer from my research, assuming you want to utilize the well-known key/secret approach. Maybe others can provide a better approach.
Basically, the approach is:
Your REST API accounts are just Cognito users in a (possibly separate) user pool
The management of API accounts is done from the back end
The username and password will be the API key and secret, are administratively created (see the Admin* operations), and can be whatever format you want (within Cognito limits)
The REST API is authorized via Cognito JWT tokens
API account key and secret are only used to retrieve or refresh tokens
This requires the REST API to have a set of endpoints to support token retrieval and refresh using account keys and secrets
Based upon how long you set up the Cognito refresh interval, you can require API accounts to submit their key/secret credentials from very often to almost never
Structuring the authorization of your REST API to use Cognito tokens will allow you to integrate the REST API directly with API Gateway's support for Cognito.
I think the biggest headache of this whole thing is that you will have to create the supporting pieces for, e.g., registered users to request API accounts and for the administration of those accounts, as well as some extra helper REST endpoints for token exchange. Additionally, clients will have to keep track of keys/secrets AND token(s) as well as add client-side logic to know when to supply tokens or credentials.
When i was starting out using API gateway and Congito, i referenced https://github.com/awslabs/aws-serverless-auth-reference-app a lot and found it very helpful in demonstrating the integration between the different AWS components.
If I understand you correctly, you want to create a "long-lived API key + secret" for programmatic access to your API?
I have exactly this need, and am sadly finding that it appears to not be possible. The longest a key can be valid for is 1 hour. You can have a refresh token that's valid for 10 years. https://docs.aws.amazon.com/cognito/latest/developerguide/limits.html
I'm currently looking for an elegant solution to this. I'd be interested to hear if you ever found a solution, or if you rolled your own.
Did anyone ever find a more elegant solution to this problem?
The first answer seems like pushing too much work into the hands of my customers. I don't know the skill level of the developers calling my API, and I wouldn't wish becoming a Cognito developer on anyone lol. More seriously, I don't want them to have to store multiple pieces of information and then have to deal with refreshing tokens.
I might be Ok with giving them a refresh token. Then I could do one of two things:
Give them a refresh method. I'd figure out all the weird Cognito kinks and keep their method to a simple payload of just the refresh token. I'd give them back the access token to use on subsequent calls.
Let them pass me the refresh token as if it was an access token. I would use it on each call to get an access token and then use that to call the interior APIs.

Authentication without user credentials

I'm putting together a personal React site and want to send requests to an AWS API Gateway. However, I just want my site to be able to pull data. There will be no user model and every auth model I've ever used requires the user to do something with sign-in, be it user/pwd or AD. Can someone guide me to a model that covers this scenario?
One common approach is to use a Cognito Identity Pool with "Unauthenticated Identities" enabled. You can secure your API gateway endpoints using IAM, and require requests to be sig4 signed.
With this approach, Cognito is used only in a kind identity broker capacity, not as an actual identity provider. You do not need to create a User Pool or use any other identity management features of Cognito. In this capacity, Cognito is essentially just a thin layer between your code and the underlying STS APIs that produce the IAM keys your application needs.
Using the Cognito SDK, you request temporary IAM credentials (access key, secret key, session token) that can be used to sign the requests.
This answer outlines one way to accomplish this. When the protected AWS resource you want to access is API Gateway, your code may look something like the example near the end of this post.
I typically either use aws-api-gateway-client, as the example does, or aws4 with axios to sign requests.
As noted in the linked to answer above, I normally use AWS.config.credentials.get(), rather than AWS.CognitoIdentity.getCredentialsForIdentity() to actually get the IAM keys (as in this doc).
The signed requests then include an Authorization header that is very difficult to counterfeit. I don't want to suggest that this approach is bulletproof, but it does at least give you a reasonable level of confidence that your API Gateway endpoints are only being successfully invoked by your application.