I'm currently exploring the AWS stack and am therefore building a simple web app. I plan on using:
S3 to host the static contents
DynamoDB to store user data
Lambda + API Gateway for backend logic
Cognito Federated Identities to authenticate users
I currently have a small tracer bullet application working that allows the user to authenticate with Google (through Cognito) and retrieve some data through a Lambda from DynamoDB. Now I want to extend it.
The next thing I want to do (and am failing to achieve) is to actually store the user name and e-mail of the authenticated user. Storing it shouldn't be a big problem, but retrieving it is. I know I initially got the data from Google because when I inspect the ID token (on JWT.io) I got from Google, I can clearly see my e-mail and name. This is the token I sent to AWS Cognito in exchange for a Cognito token.
I was expecting to be able to access this data again in my Lambda function, but I fail to figure out how actually. I understand Cognito performs a one way hash on the retrieved ID token, but I would expect some options to actually retrieve relevant user data from the token. After all, by authentication through Google (or any other IdP) a user already consented to sharing some personal data.
I feel I fail to see something obvious. Is there any feature in AWS that solves this? Is there a moment (not on the client side) where I can inspect the ID token and do some magic with it? Or should I solve this in some different way?
If the latter is the case: what would be the preferred way? I don't want users to tell me their personal data, because then I would also need some way to validate it.
Related
Just reading the docs, they seem very similar to me so I can't really discern why to use one over the other. Although identity token seems better since it has custom attributes on it from the user pool (eg: custom:blah and the default ones like name and email).
Right now, I am working with an app that passes the access token back down to the browser so it can use it for making ajax REST calls (there is an auth filter that expects this access token and validates it). Could I just switch out the access token with the id token? The current validation logic is to just get the sub field (the uuid) from the access token, but this sub field is also present in the identity token (as well as practically every other attribute except the aud which I don't need). I just want to make sure I am understanding this right as it is confusing to me why both tokens exist and seem so similar.
The id_token is for your application to process, so you can get all the personal details for your user, like their name, age, email address etc. Generally speaking you shouldn't send this token anywhere else as it contains sensitive user data.
The access_token is used to call other 'external' services (and by external I include other AWS services - these are often called over http). It provides service access authorisation for your user without having to include their personal details.
On the face of it this appears slightly confusing as you can actually use the id_token to access services in the same way as the access_token. However, good practise is to use the access_token in this circumstance and if backend services need user data, they should look it up themselves in Cognito.
EDIT: If you need to authenticate an api call based on claims in the identity token, there are circumstances when this is perfectly valid. But be aware of what details are in the identity token, and whether those claims are suitable to send to the particular API. If you don't need to use any claims from the id_token, use the access_token as this reduces the amount of potentially sensitive data you are sending.
The thing that wasn't obvious from documentation for me about the difference:
If you are using pretoken trigger function and want to add additional information to the claims with claimsToAddOrOverride , you need to use an id token because this information doesn't exist in the access token.
For ex:
event.response = {
claimsOverrideDetails: {
claimsToAddOrOverride: {
'userProfileID': id,
}
},
}
I've expected it in the AppSync resolver with lambda function as source
Speaking about AWS User Pool tokens:
Identity token is used to authenticate users to your resource servers or server applications. For example, if you use Cognito as authorizer in AWS API Gateway you need to use Identity token to call API.
The purpose of the access token is to authorize API operations in the context of the user in the user pool. For example, you can use the access token to grant your user access to add, change, or delete user attributes.
The header for the access token has the same structure as the ID token. However, the key ID (kid) is different because different keys are used to sign ID tokens and access tokens.
I'm still a learner, please forgive me if I ask a simple question. I have an application which contains its own users table where I store the email and password. When the user logs in I store the user's information (without the password) in session and privilege IDs (so that I can manage who gets to see each page after the login).
I integrated a Cognito login. How should the integration with the existing users table work? After a successful Cognito login I get a token back. Can someone write me how do I integrate the Cognito token with existing users table? Any thoughts are appreciated.
Cognito returns a JWT token which can be decoded via libraries like https://jwt.io/
The output will be somewhat like
For your use case use "cognito:username" to identify the user and store an event against it
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.
We are developing a web application in AWS which stores its users in Cognito. As part of this, we are required to have an integration with an existing desktop application, where the administrator of a client can create a read-only user for the website for data sent from the desktop app.
Because of this read-only user requirement, there has to be a user associated with the authentication for each instance of the desktop app installation. This is no problem, as we are happy that all local users of the desktop application have their data logged to the same place in the web application. The tricky part is that we are not able to have the username and password as common knowledge for the end-users of the desktop app.
It has been suggested that we could use token-based access to allow the desktop app to access our API, but these are all time limited and we would not be able to have the user re-authenticate each day. However, another suggestion is to create our own "key" which contains the username and password of the Cognito user in such a way that the application will be able to use it, such as encrypting the username and password with the decryption key available to the desktop app so that it can authenticate as that user itself without the end users having access to the account details.
I would like to know if there is currently any best practice way of handling a requirement like this that is better than what we currently have available.
To summarise:
We have an AWS API with Cognito Authentication
We have a desktop application which needs to access the API
We cannot have users know the details of the account being used to access the API
We need a way to provide a key that will allow the desktop application to authenticate itself against the API in such a way that the token will not need to be refreshed over time
Thanks for any help.
Unfortunately this requirement:
"We need a way to provide a key that will allow the desktop application to authenticate itself against the API in such a way that the token will not need to be refreshed over time"
is not going to be possible with Cognito. Assuming you are using Cognito user pools, the id and access tokens obtained on authentication are only valid for 1 hour, then they have to be refreshed using the refresh token. The refresh token can be configured to be valid for a really long time (years even) so you could setup a flow where:
The app authenticates itself against Cognito once
Gets a refresh token that is valid for a really long time
Throws away the original encrypted username/password
Uses the refresh token to get a new id/access token every hour
You would have to store the refresh token on the client somewhere though. And probably have a support mechanism where this process could be restarted on the client in case the refresh token is lost.
If you are using Cognito user pools, you are going to have to do token refreshes. Same is true if you are using Cognito identity pools - the AWS credentials provided by the identity pool are only valid for 1 hour, then they have to be refreshed.
I'm just trying to get a handle over this framework and I want to confirm that my approach is correct.
I can authenticate my own user using the method: getOpenIdTokenForDeveloperIdentity and supplying an IdentityPoolId and a Logins key-pair with my Developer provider name and a token which I provide.
Now, from what I understand, when the user logs into a second device, in order for Cognito to understand that this is the same user, I have to provide it with an IdentityId. However, I'm not sure of the best way to get the IdentityId programmatically so that it will match up with the initial login.
The only technique I can think of is to store the IdentityId in my own DB and provide my own method for retrieving it. Is this the best way? Or should I be working with this framework differently?
I'm still a beginner to AWS in general and I'm just trying to understand the best practices for this framework.
BTW, I'm implementing the Android SDK and the PHP SDK for my backend.
When you use getOpenIdTokenForDeveloperIdentity, it returns the identity id associated with the user identifier you provided. So if the user identifier you use is the users' username, when you call getOpenIdTokenForDeveloperIdentity with that same username from the second device, it will return the associated identity id. There is no need to store the identity id unless you want to, it is provided to you each time you call getOpenIdTokenForDeveloperIdentity.
This blog post may be of further help:
http://mobile.awsblog.com/post/Tx2FL1QAPDE0UAH/Understanding-Amazon-Cognito-Authentication-Part-2-Developer-Authenticated-Ident
When you use Cognito, your user first authenticates with an Identity Provider (such as facebook, google or other Oauth provider), and the token you get back from it is sent to Cognito and is the key to tying your users information together across logins on other devices.
You don't need to store this information in a database, unless you are writing you own custom identity provider and not using one of the public ones available.