Search code examples
graphqlamazon-cognitoaws-appsyncaws-amplify

How to give access to certain user groups in cognito using Appsync


I recently got into AWS and I'm using appsync alongside a dynamo table with an idex for user id(from the cognito pool) to give only certain user access to certain data. Now I would like to further expand upon this and also give access to certain cognito groups. Here is my code:

1st. my mutation

    ## [Start] Prepare DynamoDB PutItem Request. **
$util.qr($context.args.input.put("createdAt", $util.time.nowISO8601()))
$util.qr($context.args.input.put("updatedAt", $util.time.nowISO8601()))
$util.qr($context.args.input.put("__typename", "Patient"))

## This line adds the userId, accessed from the $ctx.identity variable
$util.qr($context.args.input.put("userId", $ctx.identity.sub))
$util.qr($context.args.input.put("Groupi", $ctx.identity.claims.get("cognito:groups")))



{
  "version": "2017-02-28",
  "operation": "PutItem",
  "key": {
      "id":     $util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.args.input.id, $util.autoId()))
  },
  "attributeValues": $util.dynamodb.toMapValuesJson($context.args.input),
  "condition": {
      "expression": "attribute_not_exists(#id)",
      "expressionNames": {
          "#id": "id"
    }
  }
}

and the query

#set( $limit = $util.defaultIfNull($context.args.limit, 10) )

{
    "version" : "2017-02-28",
    "operation" : "Query",
    "limit": $limit,
    "index": "userId-index",
    "query" : {
        "expression": "userId = :userId",
        "expressionValues" : {
            ":userId" : $util.dynamodb.toDynamoDBJson($ctx.identity.sub)
        }
    },
    "nextToken":   #if( $context.args.nextToken )
      "$context.args.nextToken"

     #else
     null
    #end
}

I would like to expand the query to support t6he group aswell. Help would be much appreciated. Thanks!


Solution

  • The authorization docs have lots of examples you might find helpful: https://docs.aws.amazon.com/appsync/latest/devguide/security-authorization-use-cases.html

    Specifically, this one:

    #set($expression = "")
    #set($expressionValues = {})
    #foreach($group in $context.identity.claims.get("cognito:groups"))
        #set( $expression = "${expression} contains(groupsCanAccess, :var$foreach.count )" )
        #set( $val = {})
        #set( $test = $val.put("S", $group))
        #set( $values = $expressionValues.put(":var$foreach.count", $val))
        #if ( $foreach.hasNext )
        #set( $expression = "${expression} OR" )
        #end
    #end
    {
        "version" : "2017-02-28",
        "operation" : "Scan",
        "limit": #if(${context.arguments.count}) "${context.arguments.count}" #else 20 #end,
        "nextToken": #if(${context.arguments.nextToken}) "${context.arguments.nextToken}" #else null #end,
        "filter":{
            "expression": "$expression",
            "expressionValues": $utils.toJson($expressionValues)
        }
    }
    

    That example has some extra info since it's about a list call rather than a simple get, however you can see it being set in the expression/expression values. This implementation looks a tad different than what you have as it allows a user to be in multiple groups, any one of which could work.

    Does that make sense?