Search code examples
graphqlamazon-dynamodbaws-amplifyaws-appsyncvtl

AWS Amplify Graphql Unauthorized Error - Not Authorized to access [...] on type [...]


I have an AWS Amplify App using Cognito auth

These are the affected Models/Schemas:

type Objective
@model
    id: ID!
    ..
    employee: Profile @belongsTo
    tenant: String
}
type Profile
@model
    id: ID!
    ..
    objectives: [Objective] @hasMany
    tenant: String
}

When I try to Query for list or get, the API returns the objective with all fields except employee (set to null) and also the following error message:

GraphQLResponseError message: "Not Authorized to access employee on type Objective"

Any Idea what I am missing?

I use tenant-based custom logic using customized .vtl templates in amplify which uses the authfilter (similar to the owner based approach generated by amplify). This works great with the Exception of trying to get the employee (Profile) field.

the logic looks a bit like the following:

## [Start] Authorization Steps. **
$util.qr($ctx.stash.put("hasAuth", true))
#set( $isAuthorized = false )
#set( $primaryFieldMap = {} )
#if( $util.authType() == "User Pool Authorization" )
    #if( !$isAuthorized )
        #set( $authFilter = [] )
        #set( $ownerClaim0 = $util.defaultIfNull($ctx.identity.claims.get("sub"), null) )
        #set( $currentClaim1 = $util.defaultIfNull($ctx.identity.claims.get("username"),
        $util.defaultIfNull($ctx.identity.claims.get("cognito:username"), null)) )
        #if( !$util.isNull($ownerClaim0) && !$util.isNull($currentClaim1) )
            #set( $ownerClaim0 = "$ownerClaim0::$currentClaim1" )
            #if( !$util.isNull($ownerClaim0) )
                $util.qr($authFilter.add({"owner": { "eq": $ownerClaim0 }}))
            #end
        #end
        #set( $role0_0 = $util.defaultIfNull($ctx.identity.claims.get("sub"), null) )
        #if( !$util.isNull($role0_0) )
            $util.qr($authFilter.add({"owner": { "eq": $role0_0 }}))
        #end
        #set( $role0_1 = $util.defaultIfNull($ctx.identity.claims.get("username"),
        $util.defaultIfNull($ctx.identity.claims.get("cognito:username"), null)) )
        #if( !$util.isNull($role0_1) )
            $util.qr($authFilter.add({"owner": { "eq": $role0_1 }}))
        #end
        ## begin custom auth with tenantId
        #if( $groupsInToken.contains("tenant-admin") )
            #foreach( $group in $groupsInToken )
                $util.qr($authFilter.add({"tenant": { "eq": $group }}))
            #end
        #end
        ## end custom auth
        #if( !$authFilter.isEmpty() )
            $util.qr($ctx.stash.put("authFilter", { "or": $authFilter }))
        #end
    #end
#end
#if( !$isAuthorized && $util.isNull($ctx.stash.authFilter) )
    $util.unauthorized()
#end
$util.toJson({"version":"2018-05-29","payload":{}})
## [End] Authorization Steps. **

The 'groupsInToken' will contain the corresponding tenant (id) supplied by a pretoken generation lambda.

This exact approach works fine for all Queries.

Just this Profile Object within the Objective payload seems to not be working with this approach and i can't figure out why.


Solution

  • After almost giving up i found the Solution...

    When you Query for an Nested Object "Objective.employee" one would assume that Amplify first executes the "Objective.auth.1.req.vtl" and then the "Employee.auth.1.req.vtl" and then decides whether access is granted or not.

    This is in fact not the case as Amplify generates a new Query/mutation called "Objective.employee.auth.1.req.vtl"

    So if you ever encounter the Issue

    Not Authorized to access x on type y

    try to check the x.y.auth velocity template!