How do I expose a service to different frontends? - amazon-web-services

I want to create a microservice for "orders". The service will have typical actions like "get orders" or "create an order".
I would like to expose this service in two ways:
User frontend: If you call /orders, you will see your orders
Support frontend: if you call /orders, you will see all the orders of all the users
I would like to deploy one API (orders) that can be called from 2 API gateways (user and support). But, I don't know how to do it without duplicating code.
Is this the right approach?
I'm using AWS Apigateway + Lambda + Serverless.

In some way you're being able to differentiate the user that is making the request inside your lambda function, because you need to get only its orders. Based on that I'm considering that you're receiving some kind of token in your lambda where you can extract the correct user.
Considering that scenario, one standard solution to your problem is add something to your token that differentiate if the user is from the support group or not. Normally you add a claim to the token informing that he/she is part of the support group. Then inside your lambda you check this token and give a different answer based on your requirements. But for that solution, you'll need to have means to add new claims/manage your identity provider data (user information inside your service that provides user tokens).
But with that solution you will find a small problem: if a support user must get all the orders and in another moment only its orders you won't find an easy way to implement this. If your requirements demand that you provide both use cases for support users you will need another solution.
In that case another solution would be to provide two different endpoints (API Gateway API's) touching the same backend lambda. In the normal endpoint you forward the request to the backend and the lambda gets all the orders for the user. In the support endpoint you add something else to the request (can be a query parameter or a http header).
For a more secure solution, your support endpoint must not allow requests from people outside the support group. And if you go for a query parameter alternative, you must block this exact query param in the normal endpoint. Someone can abuse the normal api sending the query param for it and get all the orders if you just forward the query params downstream.
You will do all this different configuration in the integration request of AWS API Gateway. You can find how it works here.

Related

Allowing temporary access to DynamoDB

I have a client app that connects to an Elastic Beanstalk server app. Some of my users need to register. But when the registration form loads it needs to get some data from DynamoDB so the user can choose between a few options.
The problem is that I set up my server in a way that any request to the server that is not authenticated (no auth tokens previously obtained by the client app from Cognito) gets denied. Of course, if a person is going to register they are not authenticated, which means they do not have access to the information from DynamoDB they need to register. It is only a couple of pieces of information I need, so it is very frustrating.
What I have thought about how to solve this:
Putting a long string of characters in the client app that gets sent to the server when a request is made for ONLY the couple of pieces of information I need. The server would also have that same string stored somewhere and would then compare them. If they match, then it returns the info requested. As I said, this would be done only for the 2 pieces of info I need, everything else would still be secure.
Leave the two routes public in my API that lead to the pieces of info I need (I know, it is a bad idea).
What would be the best way to go about this?
Assuming you're using cognito there is also a concept of an anonymous guest user which can have its own role assigned.
You can treat the anonymous guest user like a regular cognito user (it can have a role assigned), however you would scope its permissions down to the minimum it requires to perform these operations.
Alternatively use option 2, the API could call a Lambda that would return the necessary information simply reading the data. You would possibly want to look at caching the results as well to avoid your API Gateway endpoint being abused.

How to check for Cognito permissions in API Gateway

Trying to understand how to use Cognito and API Gateway to secure an API.
Here is what I understand so far from AWS documentation and the Cognito user interface:
Clients
www-public - public facing website
www-admin - administrators website
Resource Servers
Prices - for this simple example the API will provide secured access to this resource.
Scopes
prices.read
prices.write
Again, very simple permissions on the API. Public www users can read prices, administrators can write them.
API Gateway
GET /prices - accessible to authenticated users that can read prices.
POST /prices - only accessible to administrators
Users
Administrators - can update prices via the POST method.
Non-administrators - cannot update prices.
Based on this...
Each client will request the scopes it is interested in. So for the public www site it will request prices.read and for the administration site both prices.read and prices.write.
The API Gateway will use two Cognito Authorisers, one for each HTTP Verb. So the GET method must check the user can read prices and the POST method that they can write prices.
The bit I don't see is how to put all of this together. I can make the clients request scopes but how do they now connect to user permissions?
When the token is generated, where is the functionality that says "Ok, you requested these scopes, now I'm going to check if this user has this permission and give you the right token?"
I understand that scopes ultimately related to the claims that will be returned in the token.For example, requesting the profile scope means that the token will contain certain claims e.g. email, surname etc.
I think based on this that my permissions will ultimately end up being claims that are returned when specific scopes are asked for. The fact that the two clients differ in what they request means that the prices write claim an never be returned to the public www client. It would never issue a token if the prices.write claim was requested.
What I can't see is where this fits in Cognito. There is the option to put users into groups but that is pretty much it. Likewise, there is nothing (that I could see) to relate scopes to claims.
I'm coming from a .Net and Identity Server background. Certainly in the last version of Identity Server I looked at there was a handler method where you would work out which claims to put into a token. I guess this would map into one of the custom handler lambda functions in Cognito. From there this would need to query Cognito and work out what claims to issue?
The final piece of the puzzle is how the API Gateway checks the claims. Can this be done in API Gateway or does the token need to be inspected in the Lambda function I will write to handle the API Gateway request?
Certainly using Identity Server and .Net there was a client library you would use in the API to inspect the claims and redact permissions accordingly. Guessing there is something similar in a Node JS Lambda function?
A few assumptions there as I'm basically in the dark. I think the basics are there but not sure how to connect everything together.
Hoping someone has figured this out.

Why passing resources ids via REST API URI if they already known?

I have studied various resources for URI design best practices. Almost every author or blogger says RESTFul API URI have to look like this for example.
/* List all users in account 2 where user id is 1 */
`/users/1/accounts/2/users` [GET]
Above api caller have to pass above two ids in every request.
But my scenario is quite different.
There is a Resource Manager(RM) before my API server so every request have to pass through RM for authentication with valid token to access above example API. Note: [token send via header]
Once request is authorized in return RM provide user info i.e.(user_id, account_id etc.) to my API server via interceptor.
Question is my API server is already aware of user_id and his account_id then still there is need to get these information in API URI.
I have tried following design:
1. /users/accounts/users
2. /accounts/users
3. /users
What is best suitable design for this scenario? I spent two weeks but couldn't decide because these are enterprise APIs design; once designed than will never changed.
You should include ids in the URI for the very reason you give at the end - your API will be very difficult, maybe impossible, to change once it's being used. On the other hand, your implementation will change over time. Your authentication / authorization mechanism could change. Your enterprise may wish to move to an model which doesn't pass around ids in this fashion, and they certainly won't want to find that they have to re-design every single API which depends on the old behaviour.
At the end of the day, including enough information in the URI for the URI to identify the resource it relates to is a key part of ReST. The URI should be all that you need to identify the resource, you don't depend on out-of-band information or implementation details to further identify the resource you're addressing.

How to chain APIs using Azure API management

How to chain multiple APIs on the same URL using Azure API management?
I have two APIs the user store and that user recources api.
I want to build rest api so resources will related to user.
Mycompany/users/dani#gmail.com/resources.
User store api is mycompany/users
Resources api is mycompany/resources.
I dont want to build additional service that will consolidate this two apis.
Thanks
Additionally you can use 'send-request' policy, that will call another API endpoint and store the result in declared variable. This is what worked for me.
In my case I had hit another URL after getting response of first APIs. Same can be done in inbound policy also before getting response and similarly you can hit multiple APIs.
Policy snippet.
You can create a single API in API Management that points to multiple different backendĀ APIs. Use the set-backend-service policy to change the backendĀ API for certain operations.
I followed steps provided in this https://www.c-sharpcorner.com/blogs/api-aggregation-using-azure-apim link and able to combine two API responses within one API call.
It tells how to aggregate or chain more than one API responses in API management

Prevent AWS API Gateway from re-ordering URL parameters?

I'm attempting to port an existing API to AWS API Gateway.
I've got everything working, in that using the 'test' GUI for each of my endpoints successfully hits my configured EC2 instances.
I used the swagger import facility to automatically map all possible endpoints and their associated URL parameters.
What I've noticed is that when the request hits my API (EC2 instance) the URL has been transformed slightly. The URL parameter order has changed.
Regardless of the parameter order that I paste into the test GUI, the order of the parameters when they hit my API has been changed to the order that they are specified within the 'Method Request' GUI screen.
Does anyone know how to prevent this from happening?
There is no way to achieve this using a lambda 'custom authoriser'
I was trying to use a Lambda function as a custom authoriser which then proxies through to our HTTP API. The only data available to the custom authoriser is the 'Token' in the header (can be named anything you want - setup via API Gateway GUI). You can of course populate this with whatever values you want and one suggestion was to put the param order in this header and then perform some logic at this lambda level, however that meant modifying our API callers which wasn't desirable.
You do have access to the 'transformed' URL (e.g. 'https://df64sxl1.execute-api.us-east-2.amazonaws.com/prod/myEndpoint) but this isn't very useful.
If you are able to utilise lambda integration (instead of custom authorisation) you might be able to achieve what you by using payload-template mappings as these provide a way of accessing the raw request.