Amplify-cli: AppSync @auth Custom Claims with Dynamic Groups

Created on 4 Jan 2020  Â·  11Comments  Â·  Source: aws-amplify/amplify-cli

Which Category is your question related to?

AppSync @auth Custom Claims usage with Dynamic Groups.

Amplify CLI Version

4.9.0

What AWS Services are you utilizing?

AppSync with DynamoDB & Cognito

Provide additional details e.g. code snippets

I want to limit access to an asset based on a field value (dynamic). I have a value on each asset record called assetPlantId. I have a Cognito Group that matches this assetPlantID. So if the user is part of the Cognito Group that matches this plant then they have access. This all works really well.

type Asset  @model @auth
       (rules: [{allow: groups, groupsField: "assetPlantId", operations: [update, delete, read]}]

Problem comes that a user can only belong to 25 groups and there can only be 500 groups in a user pool. So if a company has 1,000 plants (for example) then this fails.

The answer appears to be to have a DynamoDB table where each record has the userId and the assetPlantId they are allowed access to. Then to have a Pre Token Generation Lambda Function to query DynamoDB to get all the assetPlantId's that the user is allowed to access.

However, I'm not sure how to then apply that list of assetPlantId's that were retrieved from DynamoDB and put into the JWT token with the Pre Token Generation Lamda Function and then how to apply that to the dynamic groups (groupsField).

The documentation for this is extremely sparse (https://aws-amplify.github.io/docs/cli-toolchain/graphql?sdk=js) and I'm not sure if what I outlined above is even possible using Custom Claims with Dynamic Groups.

auth question

Most helpful comment

I would ask the developer advocates in the Amplify teams for tutorials, demos, and expert guidance. They are paid to help other developers build, deploy, and operate applications. They will do a much better job than me in my free time.

Sent from my iPad

On May 23, 2020, at 7:17 AM, arkllc notifications@github.com wrote:


@RossWilliams do you mind doing a how-to detailing step by step around your solution. You can post it on medium or wherever. It will help a lot of folks including myself.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.

All 11 comments

Hi, I've done something very similar myself, you are on the right track by using the PreToken Lambda, and inside this lambda fetching information from DynamoDB. I'm guessing you have seen the documentation here. If you use the groups to override property, the access token will be updated to have the groups you specify. There should not be any other steps needed for this to work, as the generated vtl templates already read from the cognito:groups claim field to do the dynamic auth.

If instead you use the "claims to add or override", IIRC this has a quirk where it doesn't update the access token, but rather the idToken, so you would have to call your graphql endpoint with the idToken, and you would have to set the "groupClaim" auth parameter and set it to whatever you name the claim. One last tip if you use a custom claim, it requires the claim to be a string, but if you stringify the array of groups, amplify will attempt to parse the json into a list for you, so it works out in the end.

Let me know if you get stuck with anything, it took me a bit to work things out as well.

Hi @RossWilliams - that's awesome thanks. Looks like I'm on the right track. I'll let you know how I go with this. Thanks, Stephen

Hi @RossWilliams - just wanted to confirm with you that your advice here worked perfectly for us and we have now implemented it. We have the PreToken Lambda Trigger reading DynamoDB to get all groups for the current user and then override groups in the JWT Token. We didn't have to modify our schema.graphql in any way and it worked perfectly. So I didn't use custom claims (groupClaim) - just deployed a PreToken Lambda Trigger to modify the JWT Token then the [{ allow: groups, groupsField: "assetPlantI"}] as shown above just worked.

Have since deleted all groups from Cognito and now all groups are being derived from DynamoDB, so are no longer impacted by the 25 group/User and 500 group/Pool limit.

Thanks again for your help in making sure I was going in the right direction

Hi @sacrampton - Would it be possible to share your solution, I think it is what I need. I am building a system where members belong to one or many teams, can create their own team, be asked to join a team... This means their team list can be dynamic and there is a very good chance the teams will go above the cognito group limit of 500.

Are you also using something like refreshSession to force the JWT token to update under certain circumstances to ensure the user still has access? Eg: If someone has access to a team and logs in their tokens would be valid for lets say 12 hours. If a user gets access to the team revoked the JWT will still grant them access until it expires. We have an idea that if they return to the teams list it refreshes the session and removes the teams if it calls the PreToken again.

Hi @blastedcode - my use of dynamic groups is not quite as dynamic as yours is. I may have to look at that in future, but generally I probably don't need to. My scenario is that I would have Operating Unit and Plants owned by the company. An employee belongs to one or more Operating Units and there are Plants within each operating unit to which he is allowed to access. So there can quickly be more than 25 groups. That doesn't generally change - and if it does change it is not time critical so could wait for new login. Like I said, I might change that in future, but for now I'm not trying to refresh the token outside of when its generated at log in. The refreshing of the token is a separate issue to having more than 25 groups - which is all I was trying to resolve.

Having said that, I create a table in AppSync/DynamoDB called Groups to store all the groups that the user belongs to. I have Users table that stores parameters for the User and the ID of the User in that table is the sub ID from Cognito. The Groups table has the groups which the user has access. So the Pre Token Lambda function simple searches the Group table where groupUserId = Cognito sub (current user ID) - then overwrite the groups in JWT token with the groups returned from DynamoDB.

type Group @model
  @key (name: "gsi-GroupUserId", fields: ["groupUserId"], queryField: "GroupUserId") 
{
  id: ID!
  user: User @connection
  groupUserId: ID
  group: String
}

In the end it was really simple to achieve - but its not doing the refresh that you are looking for.

Thanks @sacrampton the DynamoDB table should be able to get to where I need to.

@RossWilliams do you mind doing a how-to detailing step by step around your solution. You can post it on medium or wherever. It will help a lot of folks including myself.

I would ask the developer advocates in the Amplify teams for tutorials, demos, and expert guidance. They are paid to help other developers build, deploy, and operate applications. They will do a much better job than me in my free time.

Sent from my iPad

On May 23, 2020, at 7:17 AM, arkllc notifications@github.com wrote:


@RossWilliams do you mind doing a how-to detailing step by step around your solution. You can post it on medium or wherever. It will help a lot of folks including myself.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.

I’m surprised at the limit of 500 groups, but if the limit can’t be increased, a guide walking through a custom solution would be so great.

My application has 10’s of thousands of groups with a max of 100 people in each group.

The more I get into this the more I think that Dynamic Groups should come with a big red flashing warning sign. In fact I think having them as part of @auth is something that should be removed because it breaks so many other things.

  • Firstly, there is the limit of 500 groups discussed here. There is a very good solution using a Pre-Token Lambda to get the groups for a user from a DynamoDB table rather than Cognito groups - this removes all those limitations and works well.
  • Secondly, subscriptions DO NOT WORK if you are using Dynamic Groups - so one of the big features of AppSync is not available to you if you are using Dynamic Groups
  • Thirdly, a persistent on-device storage mechanism (Data Store) does not support Dynamic Groups - you can't use Data Store if you use Dynamic Groups.

You can work around all of this, but not if you are using @auth Dynamic Groups. You need to implement Dynamic Groups in your resolvers so that your interaction with the database is honouring your Dynamic Groups - but if you use @auth to do it then some really critical functionality is not going to work for you.

@RossWilliams I did something similar using pre token lambda , if you are still interested in how to do it:

https://github.com/aws-amplify/docs/issues/2317#issuecomment-683195767

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jexh picture jexh  Â·  3Comments

onlybakam picture onlybakam  Â·  3Comments

nicksmithr picture nicksmithr  Â·  3Comments

YikSanChan picture YikSanChan  Â·  3Comments

kstro21 picture kstro21  Â·  3Comments