Retrieve user informations from cognito with ID - aws-sdk

I am trying to build a simple blog with the AWS services in order to educate myself.
I am using Amazon Cognito to log in users. Every user have a nickname. I want my user to be able to post articles to my blog.
In order to store the articles, I am using DynamoDB. Here is a sample for an article item:
{
"ArticleID": "MyUniqueID",
"title": "My Hello World Article",
"content": "This is the content of the article",
"author": "26a16b31-b2c0-4cf3-89f9-d5dcfd56d530" // Cognito User ID.
}
I'm using the serverless framework and the lambda functions to create a REST API to retrieve the documents from the database.
Now, I want to display the nickname of an author on the article page of my blog. So I somewhere have to retrieve the nickname of the 26a16b31-b2c0-4cf3-89f9-d5dcfd56d530 user.
How can I do that?
Possibilities I tried to imagine:
Using the Cognito Sync API in order to store the user informations in a DynamoDB table and add endpoints to my API to get those items.
Don't use the attributes from cognito and create a "UserProfile" externalized service
Creating an endpoint on my API to retrieve the public profile of a user (the lambda function would query the Amazon Cognito API and filter the public from the private attributes.)
How would you do that? What is the best practice for that?

I recently created a serverless app using Cognito as authentication and I am using the second option you mention. It no only makes the data consistent, but easier to get.
If you keep attributes in your UserPool it will be like managing a third party API to get his data, while the third party could be just for the authentication.
You can always keep your user data in your localstorage session.
It is much more an architectural decision than a best practice.

Related

How to get user data in AWS?

I'm trying to make a simple (React) website where a user signs in and it gets their data from a MySQL database and displays it in a table on the website. The flow is like this:
Home Page -> Sign In -> App
I want to show the user's data that is stored in a AWS RDS (MySQL) when they log into the App.
I have the domain and static hosting set up. I have a user pool set up in AWS Cognito. I set up an API Gateway with authorization and connected a basic lambda function to it. When the user signs in the are redirected to the App page with a JWT token in the header. I don't know where to go from here.
This is what I'm thinking:
User logs in, redirected to callback URL with JWT token in header.
Get the JWT token, decode it and get the user email
In my Lambda function, connect to the database instance (AWS RDS)
To query user data, select user data from a table whose name is the
users email
I don't know how to do any of the above though (apart from SQL queries). Are these even the correct steps?
How do I get the JWT token in my code? From what I know it has to be passed with every API call? I have my invoke URL from API Gateway, how do I send a request with the JWT token?
What would the database instance look like? Would it be a collection of tables that each represent a user?
How do I do this with and without AWS Amplify?
I've been trying for a few weeks but there's so much info and I feel like I'm over complicating something that is very simple to implement.
Another approach is to use the AWS SDK for JavaScript to query data on the backend and a React front end that displays the data.
This use case is located in the AWS Code Lib here:
Create an Aurora Serverless work item tracker
This example shows how to use the AWS SDK for JavaScript (v3) to create a web application that tracks work items in an Amazon Aurora database and emails reports by using Amazon Simple Email Service (Amazon SES). This example uses a front end built with React.js to interact with an Express Node.js backend.
Services used in this example
AWS Services used in this example:
Aurora
Amazon RDS
Amazon RDS Data Service
Amazon SES
Note that this example focuses on the AWS SDK, such as the RDSDataClient) and not stuff like JWT tokens, Amplify etc

How do i create api keys for users on my client instead of developer portal offered in azure api management?

I have an enpoint in my MERN app which I would like to expose to developers.
I came across APIM and would like to use it.
After going to the documentation I would like to know how do I can use APIM for my specific enpoint and where I allow users to generate API's in my client side react app.
I am also going through the API management API. but don't know how to generate user specific API keys...
You could simply mimic what the Developer Portal does using APIMs REST API.
If you are using the Consumption Tier of APIM, you can just create a standalone subscription using the Create or Update Subscription API. Yon don't have to set properties.ownerId in the request payload here.
On the other tiers, standalone subscriptions are not supported yet (but will be as mentioned in the official announcement blog under New Features), so you will have to create a user first using the Create or Update User API and then create a new subscription mentioning this user under properties.ownerId as /users/{userId}.
Since these REST APIs call the Azure Management API, you shouldn't be making these requests from the client and instead should be calling this from your backend.

How to set up Azure API Management for mult-tenant API

I have multi-tenant application, which exposes some API for our customers to use. I would like to expose it using Azure API Management. Mostly to provide Development Portal to our customers, which I find very useful, and maybe use some other features.
If I understand correctly, our customers will set up their own subscription keys for authentication, which API Management proxy will validate.
Question: How can I link and identify user/subscription to the tenant of my application, to ensure that only data from this tenant are returned.
One direction I can see to explore is to use delegated sign up, which I guess will help me to link subscription to the tenant. But then still the question is how to get user id in my backend API?
Any direction to documentation or samples is very appreciated
You could create separate groups in APIM to represent your tenants and then put users into those groups using delegation hookups. Withing APIM policy in expressions you can reference context.User.Groups to list groups user making the call belongs to and forward that information to backend.
Alternatively you could use Note field to store tenant name and access it as context.User.Note. Or if you're willing to store mapping on your side the just take an id context.User.Id.
All of above could be passed as a header using set-header policy like:
<set-header name="userId">
<value>#(context.User.Id)</value>
</set-user>
All scenarios would require you to have delegation setup to fill this information automatically for every new user created.

AWS Cognito Users + Relational Database Table. How to query/integrate both?

I'm new to AWS and I really need help with this. I have an existing RDS Schema with Users table and also with my own Users authentication algorithm/system using JWT. Everything was fine until I reached working on uploading files to S3. I discovered that when uploading to S3. We cannot pass extra parameters but only the body, key, contentType and to which bucket. I wanted to pass extra parameters like the current logged in user's access token (for user validation security), user_id, photo title and caption. But it's not possible.
What should I do? Should I use AWS Cognito User Pools instead of using an RDS Users? If I use Cognito User Pools, is it possible to do a SQL Query like joing a Cognito User and another RDS Table? I'm so confused. I'm sorry if I sound like an idiot. But I really need some help about this.
I hope somebody can. I would really appreciate it. Thank you very much in advance.
I am assuming your upload logic is in Lambda. In this case you can just do your authorization for the upload in the Lambda function. Allow the Lambda function to upload data to S3 by attaching an IAM policy to the IAM role that Lambda uses.
If you upload to S3 directly from a client, then you can either do that without authentication/authorization or use Federated Identities. In this case you can either export all your users to a Cognito User Pool (and keep them in sync) OR create your own Identity Provider and register your users for a Cognito Identity Pool.
The cleanest, but probably also hardest, way is to keep your authentication, integrate with the Cognito Identity Pool via OpenID, SAML or your own method (see http://docs.aws.amazon.com/cognito/latest/developerguide/developer-authenticated-identities.html).
You should go that way only if a) your authentication is really good and b) you have verified that having the user in a Cognito Identity Pool actually meets your requirements/business rules.

How do we deliver the API keys and secret tokens securely over the wire to the users?

How can we prevent a public API to reveal master API keys/credentials and secret tokens?
I am currently working on a webapp with some public API which should use API keys and secret tokens and were looking for a way to create a very secure API and took some look at some of the APIs of the biggest platforms, for example SoundCloud.
I read some guides (like https://github.com/interagent/http-api-design) about good (restful) API design, but they give not much information about the security (API keys and tokens) and how they should be retrieved or created in public APIs.
Take a look at https://a-v2.sndcdn.com/assets/sc-q9dV-e79e4b4a.js and search for b45b1aa10f1ac2941910a7f0d10f8e28
This is the master API key of SoundCloud.
Some of their URLs look like this:
https://api.soundcloud.com/tracks/id/stream?client_id=client_id
https://api.soundcloud.com/tracks/id/stream?secret_token=secret_token&client_id=client_id
https://api.soundcloud.com/playlists/playlist_id/?secret_token=secret_token&client_id=client_id
I know that many tools out there are already using this key for fetching/downloading all the songs from a SoundCloud user.
Also all their private and secret widgets reveal the secret tokens, also in the requests and in the sourcecode. They are hardcoded in the JavaScript code of the embed codes.
The problem consists for some years and the developers seem to have no experience with secure APIs
http://tunelab.com/2011/08/04/this-is-the-problem-with-soundcloud/
How can such APIs using JavaScript and JSON prevent to reveal these tokens and credentials?
My thoughts about this:
the master API key should be only accessible through/from soundcloud.com
there should be some sort of domain/IP blocking/restriction//firewall for all API keys
use OAUTH for all API keys, not just a simple JSON API with no authentication
dynamically generate one-time (secret) tokens, do not reuse the same token all the time dynamically get the API keys and tokens from the SoundCloud server instead of putting them into the embed codes and requests use some sort of steganography
When I read that SoundCloud is the biggest music community and big music labels upload their songs from new or upcoming albums (even as private songs and post them with a widget on websites, the secret tokens are also revealed) it seems, that the team behind SoundCloud does not want to protect their users against piracy/stealing of songs and is not willing to create a secure API.
What do you think about this critical situation on soundcloud.com and how could a JavaScript/JSON API be much more secure/secured the right way without revealing any critical data like tokens and API keys? For example using AJAX and retrieving the API key and token after the website is loaded?
How do Spotify and other streaming platforms protect the data which they are streaming and get the token and API key? Is storing these information in a URL or request URL secure at all?
How can I securely send the API key and secret token to my users over the wire using JavaScript, HTML, AJAX and PHP?
how do I deliver the API keys and secret tokens securely over the wire to the users?
There is only one reliable way: use HTTPs for your web site to allow the users to retrieve the key.
Then during the API calls HTTPS is no longer required. Your users can use HMAC authentication to hash the key with a shared secret.