#Validate Identity Id belongs to user sub

5 messages · Page 1 of 1 (latest)

crisp spoke
#

Hi team,

I see from the documentation here, https://github.com/aws-amplify/amplify-js/issues/11761, it is recommended to get the identity id from the client and save it in the DB to create a map between the identity id and user id.

On this, is there a way to validate that the identity id provided actually belongs/is related to the logged in user? Want to make sure the user is not passing someone elses identity id.

GitHub

A declarative JavaScript library for application development using cloud services. - Issues · aws-amplify/amplify-js

oak urchin
#

I'm making some assumptions about what you're looking to do, but I could see this being one of a few things.

First, this is typically what the owner field is for when going through AppSync/GraphQL. That is largely handled automatically, and it's just {sub}:{username} as far as dynamo DB is concerned.

If that's not what you're going for, maybe you mean how you would check this in a lambda function. If that's the case, these values are provided in the identity section of the event object that gets passed to the function. It's still the same sub:username deal in the DB though.

If you mean client-side, I access it through await Auth.currentAuthenticatedUser() and have to do some parsing. I've attached a screenshot for how I handle it and get it to play nice with my strict typing.

Ultimately, the sub is the user's ID as far as Cognito is concerned. The username, as far as I can tell, is just the sub as well. As far as AppSync is concerned, ownership is (by default) determined by {sub}:{username} in the owner field of any given record, but it may show up on the frontend as just the sub (but you should make sure it's always {sub}:{username} in the DB).

I hope this helps!

crisp spoke
#

Hey @oak urchin Thanks for checking in on my question.

What im looking at is the identity id used with s3 for storing user private files. As I understand, identity id is not equal to user sub. Identity id comes from the identity pool and user id from the user pool.

Now it seems only the client is able to get the identity id using what I believe is called the id token. I want to create a link in my backend db, to link the user sub to its identity id. From researching, the only way seems to be either to pass in the identity id from the frontend or to replace the access token with the idtoken when authenticating with amplify.

The former option would not work for me unless I can somehow verify that the identity id actually belongs to the authed user. The latter option is not following best practices from what I have read (still a beginner in these OICD stuff).

I hope this clarifies what I am attempting to achieve

oak urchin
# crisp spoke Hey <@251355231307169792> Thanks for checking in on my question. What im lookin...

Ahhh I think I see what's going on. The s3 buckets can be restricted so that only a particular user can do things if the object path starts with private/{user cognito ID}. The docs note that this is the sub here https://docs.amplify.aws/lib/storage/configureaccess/q/platform/js/. The access for this is determined by what's passed in the Authorization header (screenshot attached #1), which by default is the Access JWT (not the ID token).

You could replace it with the ID JWT by putting this where relevant:

Amplify.configure({
  ...config,
  graphql_headers: async () => ({
    Authorization: (await Auth.currentSession()).getIdToken().getJwtToken(),
  }),
});

and it's as secure as the normal access JWT, containing a verified signature as well. Its actually provided in the same Cognito auth request that provides the access token (screenshot attached #2).

However, I don't think you need to do this.

The ID token is a JWT provided by Cognito when the user first authenticates (or refreshes their token, or a few other events). The token is just signed (i.e. it's got a bit at the end saying it's legit and from Cognito), encoded data about the user and their current session. You can actually go here https://jwt.io/ to see what's included.

Part of that token is the Cognito user ID (the "sub"), and this is how all the Amplify backend services automatically determine authorization and ownership of stuff. But both the Access token and the ID token have that particular bit of info.

To prove I couldn't just swap the payload with a modified one, I tried it using the legit payload of another user, leaving the token's header and signature untouched, and included that in the header of a request that should have been sent to a custom Lambda GraphQL resolver (meaning it had to go through AppSync like any other GraphQL request before it could hit my Lambda function). However, it never made it to my Lambda function, because I couldn't fake the signature and was rejected with a 401 response (screenshot attached #3).

If you're curious, I use the ID token, because I wanted to include extra information that I use for permissions relating to GraphQL queries, since you can add custom stuff in the JWT payload if you use the PreTokenGeneration Cognito trigger. And this is the recommended approach in their docs here https://docs.amplify.aws/cli-legacy/graphql-transformer/auth/#custom-claims. But that's for my use case. Since it sounds like you just need the Cognito ID, I don't think you need to do that.

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

crisp spoke
#

Aaaaa I see. Thank you very much for the thorough response. Yeah this should work for my usecase. Attempting to set this up