Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to find the bidirectional map between Cognito identity ID and Cognito user information? #54

Open
baharev opened this issue Dec 10, 2017 · 107 comments

Comments

@baharev
Copy link
Contributor

@baharev baharev commented Dec 10, 2017

Given the Cognito identity ID, I would like to programmatically find the user name, e-mail address, etc. For example, one issue is that each user gets his/her own folder in S3 (e.g. private/${cognito-identity.amazonaws.com:sub}/ according to the myproject_userfiles_MOBILEHUB_123456789 IAM policy) but I cannot relate that folder name (S3 prefix) to the user attributes in my user pool. The closest thing that I have found is this rather complicated code:

AWS Lambda API gateway with Cognito - how to use IdentityId to access and update UserPool attributes?

Is it my best bet? Is it really this difficult?

(As a workaround, I would be happy with a post confirmation lambda trigger that creates for example a ${cognito-identity.amazonaws.com:sub}/info.txt file in some S3 bucket, and in the info.txt file it could place the user sub from the user pool. I am not sure that this is feasible at all, it was just an idea.)

@jonsmirl

This comment has been minimized.

Copy link

@jonsmirl jonsmirl commented Jan 5, 2018

When the identity is created in the identity pool, can't you add 'logins' to the call? Those logins get stored in the identity pool providing a way to map between Google/Facebook/User Pool ID and the Identity pool ID. 'Logins' are optional, but they are very useful.

--logins (map)
A set of optional name-value pairs that map provider names to provider tokens.

Edit - you have the logins in Auth.ts/setCredentialsFromFederation.
Why aren't these getting stored in the identity pool along with the ID from federation, I'm sure that data used to be in my identity pools, so where did it go?

Here's an identity pool entry from my mobile app, it has the User Pool ID in it. The mobile app is based on code from Mobile Hub.

jonsmirl@ubuntu-16:~$ aws cognito-identity describe-identity --identity-id us-east-1:bea3f57c-4564-47cf-b82c-a515f719d8a5 --profile bill
{
"Logins": [
"cognito-idp.us-east-1.amazonaws.com/us-east-1_Cf6AJpe20"
],
"LastModifiedDate": 1512005509.277,
"CreationDate": 1512005509.237,
"IdentityId": "us-east-1:bea3f57c-4564-47cf-b82c-a515f719d8a5"
}

I checked Google and FB logins and they don't display the Google/FB sub like the user pool entry does.

So my mobile app is storing the User Pool ID. This seems to be missing from amplify. If that data was in the identity pool this issue would be solved.

In Auth.ts there is this code:
private setCredentialsFromFederation(provider, token, user) {
const domains = {
'google': 'accounts.google.com',
'facebook': 'graph.facebook.com',
'amazon': 'www.amazon.com'
};

I wonder if that string is fixed format? Maybe it is legal to say...
'google': 'accounts.google.com/34455444444',

ie add in the Google sub id? That appears to be what the mobile hub code did for Cognito.

@richardzcode

This comment has been minimized.

Copy link
Contributor

@richardzcode richardzcode commented Jan 27, 2018

Hi @baharev lookup user attributes by identityId is application specific. Some app may not want this for security concerns, some want to store in S3, and some prefer database. As a library we can't make those assumptions.

With aws-amplify it is pretty easy to implement. Depend on your needs, maybe pick one of the below two implementation.

Save private so only owner of the info can access

When user sign up, or maybe sign in depend on your choice,

  Auth.currentUserInfo()
    .then(info => {
      Storage.put(
        'userInfo.json',
        JSON.stringify(info),
        { level: 'private', contentType: 'application/json' }
      );
    });

Then do this to load user attributes,

  Storage.get('userInfo.json', { level: 'private',  download: true})
    .then(data => console.log('info...', data.Body.toString()));

Save public so just lookup by identityId

  Auth.currentUserInfo()
    .then(info => {
      Storage.put(
        identityId + '_userInfo.json',
        JSON.stringify(info),
        { level: 'public', contentType: 'application/json' }
      );
    });

Then do this to retrieve user attributes,

  Storage.get(identityId + '_userInfo.json', { level: 'public',  download: true})
      .then(data => console.log('info...', data.Body.toString()));
@baharev

This comment has been minimized.

Copy link
Contributor Author

@baharev baharev commented Jan 27, 2018

@richardzcode Thanks, your first suggestion is an acceptable workaround for the time being. What I don't like about it is that the userInfo.json in your code comes from the user, and therefore cannot be trusted.

lookup user attributes by identityId is application specific.

There is a misunderstanding here: I need this bidirectional map purely on the backend. The user must not be able to access it exactly for security reasons.

The use cases are the followings.

  1. If a user is complaining about a bug, I have to be able to find his/her folder to look at the data and to reproduce the bug (if any). In this use case I know the user but I don't know which folder is his/her folder.
  2. Say I noticed something strange in certain folders of the S3 bucket, and I would like to reach the corresponding users in e-mail and warn them. In this use case I know the folder but I don't know the users' e-mail address.

Note that both use cases must happen purely on the backend, and without any interaction from the user.

The true solution would be to retrieve this bidirectional map purely on the backend, without any user interaction. I think there should be an AWS API for backend code to do that. In my first comment I link to a horribly complicated "solution", but I find that unacceptably complex.

@baharev

This comment has been minimized.

Copy link
Contributor Author

@baharev baharev commented Jan 27, 2018

I looked at the Cognito API reference, and it is weird too. For example:

  1. AdminGetUser does not seem to give me the identity ID.
  2. DescribeIdentity does not seem give me any user attributes.
  3. Somehow the mapping between users and identity IDs seem to be hidden. The only way I could recover it is through the login tokens.

What is going on here? Or what did I miss / misunderstand?

@richardzcode

This comment has been minimized.

Copy link
Contributor

@richardzcode richardzcode commented Feb 1, 2018

@baharev In my knowledge there is no backend direct mapping between identityId and username. Backend is depend on what services provide. We can only suggest client side solution at this moment.

@jonsmirl

This comment has been minimized.

Copy link

@jonsmirl jonsmirl commented Feb 1, 2018

The old Mobile Hub code for Android built a two way map. This Indentity pool entry was created by that code when I did a user pool login:

jonsmirl@ubuntu-16:~$ aws cognito-identity describe-identity --identity-id us-east-1:bea3f57c-4564-47cf-b82c-a515f719d8a5 --profile bill
{
"Logins": [
"cognito-idp.us-east-1.amazonaws.com/us-east-1_Cf6AJpe20"
],
"LastModifiedDate": 1512005509.277,
"CreationDate": 1512005509.237,
"IdentityId": "us-east-1:bea3f57c-4564-47cf-b82c-a515f719d8a5"
}

Also, if you use the current hosted UI under user pool it creates a back link like above. It is only Amplify that is not creating the back link.

I just used Amplify to create an entry in my identity pool corresponding to a userpool entry. The entry in the identity pool does not have the linked login info shown above.

jonsmirl@ubuntu-16:~/aosp/demo/foobar/client$ aws cognito-identity describe-identity --identity-id us-east-1:f763ea29-41ce-4b86-bc58-31de68d7cce8
{
"LastModifiedDate": 1517513923.798,
"CreationDate": 1517513923.798,
"IdentityId": "us-east-1:f763ea29-41ce-4b86-bc58-31de68d7cce8"
}

@baharev

This comment has been minimized.

Copy link
Contributor Author

@baharev baharev commented Feb 1, 2018

@richardzcode This map must exist on the backend, because a given user always gets the same ${cognito-identity.amazonaws.com:sub}. It must be solvable purely on the backend.

@baharev

This comment has been minimized.

Copy link
Contributor Author

@baharev baharev commented Feb 1, 2018

@jonsmirl Sorry, I don't understand, but it seems to me that you are also struggling with this issue, or with a very similar one.

@jonsmirl

This comment has been minimized.

Copy link

@jonsmirl jonsmirl commented Feb 1, 2018

When amplify creates an entry in identity pool corresponding to a user pool entry, why is this part missing? Other Amazon Cognito code makes this entry:

"Logins": [
"cognito-idp.us-east-1.amazonaws.com/us-east-1_Cf6AJpe20"
],

That entry lets you map from an identity pool ID back into a user pool ID. You can query the logins off from an identity pool entry to get that string. Then use that string to query all of the attributes for the user out of the user pool.

@baharev

This comment has been minimized.

Copy link
Contributor Author

@baharev baharev commented Feb 1, 2018

@jonsmirl OK, now we are getting somewhere. Please explain:

Then use that string to query all of the attributes for the user out of the user pool.

How? Which API call will consume this mysterious "cognito-idp.us-east-1.amazonaws.com/us-east-1_Cf6AJpe20" and give me the user attributes?

@jonsmirl

This comment has been minimized.

Copy link

@jonsmirl jonsmirl commented Feb 1, 2018

We don't use this feature, and I see now that I was misunderstanding what I was seeing. This is the Cognito user pool id, not the sub of the user: cognito-idp.us-east-1.amazonaws.com/us-east-1_Cf6AJpe20
I was thinking that last part was the sub of the user in the pool and it is not.

You would need to be able to access the token that was submitted with this identity and I don't see any obvious way to get to it. 99% of our logins are via Google/FB with only a few using User Pool.

So to make this work, after you get logged in you will need a dynamodb table that maps the cognito identify id to the cognito user id. Then you will be able to find the user in the user pool.

Or you will just end up doing what we did. Since the attributes on Google, FB and user pool are all different we just store a copy of the attributes we care about in our internal user database. Which is what richard said to do.

This might be what you are looking for:

https://stackoverflow.com/questions/42386180/aws-lambda-api-gateway-with-cognito-how-to-use-identityid-to-access-and-update

@baharev

This comment has been minimized.

Copy link
Contributor Author

@baharev baharev commented Feb 1, 2018

@jonsmirl Thanks for the prompt reply.

As I said, yes, it would be an acceptable workaround for the time being, but it requires a user login and the info comes from the user (hence cannot be trusted). What pisses me is that this map must be available in the backend, so I see no reason why the user pool owner cannot access it. It just does not make sense to me, and I am wondering why the others aren't complaining about it too.

This might be what you are looking for:

https://stackoverflow.com/questions/42386180/aws-lambda-api-gateway-with-cognito-how-to-use-identityid-to-access-and-update

That is the link in my very first comment. :) I know you can do it, but it is unacceptably complex.

Thanks again for the prompt feedback!

@WolfWalter

This comment has been minimized.

Copy link

@WolfWalter WolfWalter commented Feb 25, 2018

Totally agreeing with @baharev. In my use case I have stored the Cognito Identity IDs in my database and now tried to get the username of the associated userpool user. None of the APIs seems to expose this functionality.

@ffxsam

This comment has been minimized.

Copy link
Contributor

@ffxsam ffxsam commented Mar 4, 2018

I was advised to retrieve the Cognito identity ID via Auth.currentUserInfo() and store it as an attribute in the user object in the user pool.

@ffxsam

This comment has been minimized.

Copy link
Contributor

@ffxsam ffxsam commented Mar 4, 2018

However, I can't figure out when the right time is to grab this info. Upon login, when I call Auth.currentUserInfo(), the id property is undefined.

  async signIn({ commit }, { username, password }) {
    const user = await Auth.signIn(username, password);
    const userInfo = await Auth.currentUserInfo();
    console.log(userInfo);
    authenticate(commit, user);
  },
@ffxsam

This comment has been minimized.

Copy link
Contributor

@ffxsam ffxsam commented Mar 4, 2018

Ok, this works for me:

  async signIn({ commit }, { username, password }) {
    const user = await Auth.signIn(username, password);
    const credentials = await Auth.currentCredentials();
    console.log('Cognito identity ID:', credentials.identityId);
    authenticate(commit, user);
  },

So within this code block, you could just update the user's attributes and set their Cognito identity ID in there, and you'd have immediate access to it once they're authenticated.

@baharev

This comment has been minimized.

Copy link
Contributor Author

@baharev baharev commented Mar 4, 2018

@ffxsam Interesting, thanks for letting us know. I recognize Auth.signIn() and Auth.currentCredentials() but could you explain what authenticate is in your code?

If I understand correctly what you are suggesting, it is essentially the same as richardzcode's suggestion. See my previous objections why I am not happy with it as a solution. It is an acceptable workaround for the time being though.

@ffxsam

This comment has been minimized.

Copy link
Contributor

@ffxsam ffxsam commented Mar 5, 2018

authenticate isn't relevant here, just my own function that commits data to a Vuex store.

@gbrits

This comment has been minimized.

Copy link

@gbrits gbrits commented Mar 13, 2018

This is how I overcame the obstacle of not having the identityId on hand for my users:

login() {
    let loading = this.loadingCtrl.create({
      content: 'Please wait...'
    });
    loading.present();

    let details = this.loginDetails;
    Auth.signIn(details.username, details.password)
      .then(user => {
        Auth.currentCredentials().then(credentials => {
          var identityId = credentials.identityId;
          let params = {
             "AccessToken": user.signInUserSession.accessToken.jwtToken,
             "UserAttributes": [
                {
                   "Name": "custom:identityId",
                   "Value": identityId
                }
             ]
          }
          // Save the identityId custom attribute to the user
          this.db.getCognitoClient()
          .then((client) => {
            client.updateUserAttributes(params, function(err, data) {
                if (err) console.log(err, err.stack);// an error occurred
                else {
                  console.log(data);
                }
            });
          });
        });
        logger.debug('signed in user', user);

        if (user.challengeName === 'SMS_MFA') {
          this.navCtrl.push(ConfirmSignInPage, { 'user': user });
        } else {
          this.navCtrl.setRoot(TabsPage);
        }
      })
      .catch(err => {
        logger.debug('errrror', err);
        this.error = err;
      })
      .then(() => loading.dismiss());
  }

Ref: inside of my DynamoDB (public db) class, my getCognitoClient method invokes the CognitoIdentityServiceProvider endpoint from the aws-sdk

getCognitoClient() {
      return Auth.currentCredentials()
        .then(credentials => new AWS.CognitoIdentityServiceProvider({ credentials: credentials }))
        .catch(err => logger.debug('error getting document client', err));
  }

Important Note You have to log into Cognito's User Pool and click Attributes and add IdentityId (as a string) to your custom attributes, for it to be populated.

Hope this helps someone. Because it had me thinking I'm an idiot who should stop programming, so hopefully someone out there can reassure me to continue!

@baharev

This comment has been minimized.

Copy link
Contributor Author

@baharev baharev commented Mar 17, 2018

@gbrits I think that we should get official support through the SDK, and we really should not be implementing our workarounds. Especially not in ways that involve data coming from the user (untrusted data).

As far as I understand your code, it has the same issues as richardzcode's workaround.

@ffxsam

This comment has been minimized.

Copy link
Contributor

@ffxsam ffxsam commented Mar 18, 2018

Totally agree. The SDK should handle these sorts of lower level operations for us.

@Shadaeiou

This comment has been minimized.

Copy link

@Shadaeiou Shadaeiou commented Jul 28, 2019

@baharev I wasn't asking for help I was just saying I'm also in the same boat and desire this feature.

@baharev

This comment has been minimized.

Copy link
Contributor Author

@baharev baharev commented Jul 28, 2019

@Shadaeiou Then please tell that to one of the AWS developers on this thread. This issue is the oldest open issue and also the most commented one. I don't understand why it has such low priority.

@keithdmoore

This comment has been minimized.

Copy link

@keithdmoore keithdmoore commented Jul 28, 2019

@babu-upcomer

This comment has been minimized.

Copy link

@babu-upcomer babu-upcomer commented Aug 19, 2019

ah @baharev, you deserve a medal! Like @Can-Sahin said, it took me a day to realize that it still isn't possible and sad to see this has been a point of discussion for the last 2 years comparing how AWS is promoting Amplify as an inhouse serverless stack out there. Has this been raised in amplify-cli repo? I just have hit with the same issue but on a different context. Giving up on this one for now.

@baharev

This comment has been minimized.

Copy link
Contributor Author

@baharev baharev commented Aug 19, 2019

@babu-upcomer As for amplify-cli, the first red flag was when its predecessor (awsmobile-cli) silently and irrecoverably deleted the S3 bucket with the users' files. More red flags followed, then I ultimately stopped using amplify-cli when it required full admin access to my AWS account, and I refuse to use it. Due to the bugs I encountered, I simply don't trust it. Just look at the issues I raised in the awsmobile-cli, amplify-cli and amplify-js repos.

I have rewritten everything from Amplify on the top of the AWS JavaScript SDK that I need except Auth. The reason for not rewriting Auth is that it is non-trivial and I don't have the time at the moment to do it. But it is coming...

By the way, it is fairly easy to rewrite, for example, Storage (S3) on the top of the AWS JavaScript SDK: 15 lines of code, and then you have full control. Accessing DynamoDB is equally easy with the AWS JavaScript SDK.

I rolled my own deployment script, less than 200 lines and it does pretty sophisticated things (for example compression and cache control for CloudFront the way I want it). Now I control how Storage works, or how deployment is done. Again, look at the issues I raised in the awsmobile-cli, amplify-cli and amplify-js repos.

As for this particular issue #54, I am working towards an approach similar to what @lestephane sketched in his comment. It turns out that after restructuring my application, a similar approach works for me too. It is admittedly a workaround, but at least I will have full control. I will still depend on Auth though...

@baharev

This comment has been minimized.

Copy link
Contributor Author

@baharev baharev commented Aug 19, 2019

@babu-upcomer As a side note: Even if this issue is resolved, you would want to assign your unique ID to each user in a way you control. From the comment of @RossWilliams:

I’d much rather have a choice of claim to use and I’d like to avoid sub as it’s not under my control and cannot be recreated when restoring a Cognito User Pool. Anything that relies on a sub would be a large operations risk and require a lot of tooling and time to overcome.

in the related issue Can we use the sub instead of identity id for private/protected storage?

@Vingtoft

This comment has been minimized.

Copy link

@Vingtoft Vingtoft commented Aug 21, 2019

I cannot believe this problem has not been fixed yet. People are burning so much time!!!!

@vahdet

This comment has been minimized.

Copy link

@vahdet vahdet commented Sep 4, 2019

So, I also jump on the bandwagon. Getting another user's protected file through AWS Amplify requires the identityId such as:

Storage.get('test.txt', { 
    level: 'protected', 
    identityId: 'xxxxxxx' // the identityId of that user
})
.then(result => console.log(result))
.catch(err => console.log(err));

So, I should get that identityId not for the current user, but also for other ones!

@davidolmo

This comment has been minimized.

Copy link

@davidolmo davidolmo commented Sep 19, 2019

Lol, I was not expecting an issue this old to keep open. I'm facing exactly the same problem. I come from Google firebase and this was super easy to accomplish with the SDK. +1 to please solve this

@djkmiles

This comment has been minimized.

Copy link

@djkmiles djkmiles commented Oct 2, 2019

This took us about 8H to solve, the tidiest secure solution we currently have for our closed AppSync + Cognito UP + Cognito IP / AWS system is running a Lambda as a mutation that takes no parameters. The user's exact current JWT is put into the Lambda request by the AppSync VTL resolver along with the CUP ID and then the Lambda requests the Cognito IP user-identity using the CognitoIdentity module and then writes it into the "Users" DDB table using the CUP ID so it can be looked up when needed.

AppSync Lambda-request:

{
	"version" : "2017-02-28",
	"operation": "Invoke",
	"payload": $util.toJson({
		"sub": $ctx.identity.sub,
		"jwt": $ctx.request.headers.authorization
	})
}

Lambda:

const AWS = require('aws-sdk')
const cip = new AWS.CognitoIdentity()
const ddb = new AWS.DynamoDB.DocumentClient()

exports.handler = async ({ sub, jwt }, context, callback) => {
	let { IdentityId: id } = await cip.getId({ IdentityPoolId: process.env.IDENTITY_POOL_ID, Logins: { [process.env.USER_POOL_ID]: jwt } }).promise()
	await ddb.update({ TableName: 'Users', Key: { id: sub }, UpdateExpression: 'set identityToken = :id', ExpressionAttributeValues: { ':id': id } }).promise()
	callback(null, {})
}
@kevin-mitchell

This comment has been minimized.

Copy link

@kevin-mitchell kevin-mitchell commented Dec 1, 2019

Hi all, I'm going to be honest and say that despite a fair amount of reading I'm not entirely sure if the question that I have is related to this ticket or not. I'm just getting into Amplify really, and Cognito, so it's a bit confusing to me at the moment.

My specific use case (I'm hoping somebody can tell me if I'm just crazy) is that I am using PubSub with Amplify, and when a user registers I need to setup some permissions - basically I need to do the equivalent of aws iot attach-principal-policy --policy-name 'myIoTPolicy' --principal '<YOUR_COGNITO_IDENTITY_ID>' but I'd like to automate this on user signup.

This would require that in the PostAuthentication_Authentication trigger I am able to get the users Cognito Identity ID... but from what I can tell, that's not possible?

It seems like perhaps the reason this isn't possible should be more obvious, but there seems like there should be SOME relationship between the user pool user and the federated cognitio identity? But from what I can tell, within these hooks I don't have access.

I'm guessing the fact that this is so confusing to me shows there is a fundamental (and significant!) gap in my understanding of how these systems should be used.

My plan for now, to work around this, is to use a different trigger (an API call) where I know I have access to the Cognito Identity ID. I guess this is likely because when you are making API calls, you're doing so as a federated user, not as a user from a "user pool"?

@baharev

This comment has been minimized.

Copy link
Contributor Author

@baharev baharev commented Dec 1, 2019

@kevin-mitchell If I interpret your post properly: Yes, problem well spotted, and yes, apparently that's the best workaround for the time being. Welcome to the club!

@svenmilewski

This comment has been minimized.

Copy link

@svenmilewski svenmilewski commented Dec 2, 2019

My specific use case (I'm hoping somebody can tell me if I'm just crazy) is that I am using PubSub with Amplify, and when a user registers I need to setup some permissions - basically I need to do the equivalent of aws iot attach-principal-policy --policy-name 'myIoTPolicy' --principal '<YOUR_COGNITO_IDENTITY_ID>' but I'd like to automate this on user signup.

This would require that in the PostAuthentication_Authentication trigger I am able to get the users Cognito Identity ID... but from what I can tell, that's not possible?

My plan for now, to work around this, is to use a different trigger (an API call) where I know I have access to the Cognito Identity ID. I guess this is likely because when you are making API calls, you're doing so as a federated user, not as a user from a "user pool"?

This is exactly my use case. We're using an AppSync mutation for that right now to trigger the policy attachment. But, yeah, this is definetily not the clean way...

@mfogel

This comment has been minimized.

Copy link

@mfogel mfogel commented Dec 4, 2019

What we are doing to solve this problem, which has worked ok so far, is we set the user pool Username to match the IdentityId from the identity pool when creating a new user. Since they match, the bidirectional mapping between the two services is now pretty trivial ;)

The new user signup flow goes like this:

  • pull an unauthenticated IdentityId from the identity pool using getId()
  • call signUp() on the user pool, passing in the IdentityId from the previous call as the new user's Username (we put their human-readable username in preferred_username)
  • then after user has confirmed their email/phone and signed in to the user pool, we link the user pool entry back to the identity pool entry by calling getCredentialsForIdentity() using same IdentityId/Username from before along with the IdToken from the user pool

We implemented this first with the lower-level SDK's linked to above. I didn't handle the mapping of this up to amplify but I understand that was a non-trivial task.

And obviously this won't work so well if you already have a bunch of users, but if you're building a new app like we are, hopefully this works for you too.

@WGriffing

This comment has been minimized.

Copy link

@WGriffing WGriffing commented Dec 18, 2019

I am going to add in another possible solution here, but it may be of limited value and may have other drawbacks. I will not profess to be any kind of AWS or Amplify expert so if you see an issue with using this approach I would be happy to hear from you.

I found that it is possible to use a lambda authorizer (of type TOKEN, other types may be possible, but I did not test). We were already utilizing a lambda authorizer to add additional context information into our APIs so this seems like a good fit. It's still early days so I'm not sure if we'll hit any rate limits or other problems. Consider this to be an untested/alpha solution.

  1. Utilize the JWT, along with some environment variables for things like pool ID to call boto3's get_id method from the cognito-identity client.
  2. The response of that method will contain IdentityId. Use this IdentityId to call attach_principal_policy from boto3's iot client.

Example snippet from my API's lambda authorizer:

import os
import boto3

CLIENT_COGNITO = boto3.client('cognito-identity')
CLIENT_IOT = boto3.client('iot')
IDENTITY_POOL_ID = os.environ.get('IDENTITY_POOL_ID')
IOT_TOPIC_POLICY = os.environ.get('IOT_TOPIC_POLICY')
REGION = os.environ.get('REGION', 'us-east-1')
USER_POOL_ID = os.environ.get('USER_POOL_ID')

def setup_iot(token, context):
    account_id = context.invoked_function_arn.split(":")[4]
    logins = {}
    logins['cognito-idp.{}.amazonaws.com/{}'.format(
        REGION, USER_POOL_ID)] = token

    id_response = CLIENT_COGNITO.get_id(
        AccountId=account_id,
        IdentityPoolId=IDENTITY_POOL_ID,
        Logins=logins
    )

    identity_id = id_response['IdentityId']
    CLIENT_IOT.attach_principal_policy(
        policyName=IOT_TOPIC_POLICY,
        principal=identity_id)

def lambda_handler(event, context):
    token = event['authorizationToken']
    claims = verify(token) # not shown, but responsible for verifying the JWT
    principal_id = claims.get('cognito:username', None)

    if not principal_id:
        raise Exception('Unathorized')

    setup_iot(token, context)
    <other code removed>
@chintanvyas360

This comment has been minimized.

Copy link

@chintanvyas360 chintanvyas360 commented Feb 26, 2020

Surprised to see that this issue is open since Dec 2017 and AWS hasn't provided any fix nor documentation to hep customers. Based on a cursory read and the no. of hacks listed on this issue, it seems obvious that it should not be left to customers and should be a P0 priority in terms of features.

Ours is a SaaS application using AWS Amplify and we need a link between the Cognito Identity ID and the username for the below-mentioned use cases:

  1. Customer Support - "My name is this, I tried to upload this x file but it failed, could you please check?" There's no way we can map the S3 file path for that cognito identity ID to the username.
  2. Content Moderation - A user uploads some content which shouldn't be on the platform, we need to automatically email the user regarding this but can't because although we have the identity ID, we don't have associated user attributes.
  3. Storage Limit and other checks - we need to monitor application usage and trigger alerts if customers are exceeding storage tier thresholds. Same problem!

Not sure which team is taking it up (Cognito or Amplify) but it seems that they need to work it out. Sorry if it sounds rude but it's a valid critical concern and we haven't been able to get around this.

@keithdmoore

This comment has been minimized.

Copy link

@keithdmoore keithdmoore commented Feb 26, 2020

Due to this issue, I will never use AWS Cognito again. Likewise, I will not be using or recommending Amplify as well due to this issue being completely disregarded.

@rdsedmundo

This comment has been minimized.

Copy link

@rdsedmundo rdsedmundo commented Feb 26, 2020

I think we should make a template and send a support inquiry to AWS with the same content pointing to this issue, demanding an answer. We're paid customers, and it's been 2 years and counting that we had no conclusive response other than someone coming and adding a few labels to the issue saying that it's on a backlog.

@alexofob

This comment has been minimized.

Copy link

@alexofob alexofob commented Mar 9, 2020

Amplify is full of surprises. Easy things are not simple as they say. This issue should not be open till now.

@annjawn

This comment has been minimized.

Copy link

@annjawn annjawn commented Mar 10, 2020

This problem has come back to bite me in my 5th project so far with Amplify. It makes no sense that there is no bi-directional mapping between User Pool and the Identity Pool identities. Especially, in case of Federated user pool. I have federated User pool with SAML, Google, and Facebook and mapping which user is the identity in the identity pool has been a pain in the behind unless we do some hacks like reading the JWT idToken to get the Identity ID and then store it somewhere for later reference.

This also makes it super painful to use the Storage module especially the protected level since protected levels needs the identity ID to access a user's file. This is fine for the current user and they can access their "own" file(s) from the private and protected prefixes in S3, but what about accessing (GetObject) other user's files from the protected prefix since the definition of protected says you can read any other user's protected file but not write to it. This is painful because now the current user needs to know ALL the other user's identity ID in advance of making use of the Storage.get API. This to me sounds more like an issue for AWS Cognito team to solve than for Amplify.

@babus

This comment has been minimized.

Copy link

@babus babus commented Mar 10, 2020

Hmm, this is an early sign of AWS abandoning Amplify. I would recommend anyone to move away from Amplify whenever possible. There have been so many promises in the documentation at-least with the way it was written but then the product manager like me end up burning my dev's time just to hit into a dead end in future.

@undefobj

This comment has been minimized.

Copy link
Contributor

@undefobj undefobj commented Mar 10, 2020

@babus Amplify is not being abandoned by any means, in fact we invest into it more every day. We are in discussions on this issue with the Cognito team.

@annjawn

This comment has been minimized.

Copy link

@annjawn annjawn commented Mar 10, 2020

I think Amplify has had some major improvements since AWS Mobile Hub days, but I think specific to Cognito as a service, there's also much work to be done. I am eager and excited to see those improvements coming up in the future.

@babus

This comment has been minimized.

Copy link

@babus babus commented Mar 11, 2020

@undefobj That's glad to hear. But let's solve it first and then talk. This issue is basically a very root issue with not so ever understanding of how cognito and storage work together and it's been here for the past 2 years.

To the downvoters, people are paying to AWS by using Amplify and this isn't just a open source library where I cannot be toxic. This is a paying customer expecting some basic level of customer satisfication from the vendor. Even their business level technical support team doesn't have any clue when this would be solved.

@peterschwarz21

This comment has been minimized.

Copy link

@peterschwarz21 peterschwarz21 commented Mar 21, 2020

I can't believe this thread is still open.... I'll just mention that I am facing the same problem albeit different.

I am using the CognitoID as the UID for users in my own DB. No problems except when the project scope changed to allow 'admin' users to add other users to their application, there is no way of getting this ID when creating the user in the UserPool.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
You can’t perform that action at this time.