question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Two mutations showing as not authorized, but still being executed

See original GitHub issue

Bug report

  • I have checked other issues to make sure this is not a duplicate.

Describe the bug

We have two mutations that are always returning the fallback error. All other mutations are pointed to the same rule, and perform as expected, but these mutations execute the rule, and even execute the mutation, but still throw the fallback error. Even when explicitly set to allow.

The odd part though, is that those mutations are actually executed, but they still throw an error as if they weren’t ever allowed to execute.

To Reproduce

Here is our setup:

import { rule, allow, deny, shield } from "graphql-shield";
import { IOptionsConstructor } from "graphql-shield/dist/types";
import { jwtService } from "../contexts/context";
import { CONFIG } from "../config/config";

export class AuthorizationHandler {

    isAuthenticated = rule()(async(parent, args, ctx, info) => {
        if (CONFIG.disableAuth && CONFIG.disableAuth === true) {
            return true;
        }

        let token = ctx.headers.authorization;
        if (token) {
            try {
                return await jwtService.validateToken(token);
            } catch (err) {
                return err;
            }
        }

        return false;
    });

    // Create the shield rule with all the blocked and allowed rule
    createShield(): any {
        return shield(
            {
                // Query level restriction
                Query: this.isAuthenticated,

                // Mutation level restriction
                Mutation: {
                    createAccount: this.isAuthenticated,
                    updateAccount: this.isAuthenticated,
                    updateAccountUser: this.isAuthenticated,
                    createAccountUser: this.isAuthenticated,
                    createApp: this.isAuthenticated,
                    updateApp: this.isAuthenticated,
                    createDataGroup: this.isAuthenticated,
                    updateDataGroup: this.isAuthenticated,
                    deleteDataGroup: this.isAuthenticated,
                    createFavorite: this.isAuthenticated,
                    deleteFavorite: this.isAuthenticated,
                    updateFavorite: this.isAuthenticated,
                    createNavigationItem: this.isAuthenticated,
                    createNavigationItems: this.isAuthenticated,
                    deleteNavigationItemAndRoleOverrides: this.isAuthenticated,
                    deleteNavigationItemAndNavigationItemOverrides: this.isAuthenticated,
                    updateNavigationItem: this.isAuthenticated,
                    upsertNavigationItemOverrides: this.isAuthenticated,
                    createNotePad: this.isAuthenticated,
                    deleteNotePad: this.isAuthenticated,
                    updateNotePad: this.isAuthenticated,
                    upsertNotePad: this.isAuthenticated,
                    createNotification: this.isAuthenticated,
                    updateNotification: this.isAuthenticated,
                    createProgram: this.isAuthenticated,
                    updateProgram: this.isAuthenticated,
                    createRole: this.isAuthenticated,
                    updateRole: this.isAuthenticated,
                    upsertRoleOverrides: this.isAuthenticated,
                    createSettings: this.isAuthenticated,
                    updateSettings: this.isAuthenticated,
                    deleteSettings: this.isAuthenticated,
                    createUserGroup: this.isAuthenticated,
                    updateUserGroup: this.isAuthenticated,
                    createUserProfile: this.isAuthenticated,
                    updateUserProfile: this.isAuthenticated,
                    updateUserProgram: this.isAuthenticated,
                    updateManyUserPrograms: this.isAuthenticated,
                    updateManyUserProfiles: this.isAuthenticated,
                    createUserProgram: this.isAuthenticated
                },

                // Type level restriction
                Account: allow,
                AccountUser: allow,
                App: allow,
                DataGroup: allow,
                Favorite: allow,
                NotePad: allow,
                Notification: allow,
                NavigationItem: allow,
                NavigationItemOverride: allow,
                Program: allow,
                Role: allow,
                RoleOverride: allow,
                Settings: allow,
                System: allow,
                UserProfile: allow,
                UserGroup: allow,
                UserProgram: allow
            },
            this.options()
        );
    }

    // Set the configuration for the Shield rule
    private options(): IOptionsConstructor {
        return {
            fallbackRule: deny,
            fallbackError: 'Not Authorized! You either don\'t have permission to perform this mutation or the mutation has not been added to the list of authorized mutations.',
            allowExternalErrors: true
        }
    }
}

The updateManyUserProfiles and updateManyUserPrograms always throw our fallback error. All other mutations perform as expected and run through that rule. Those two mutations are actually executed, they just throw an error as if they hadn’t been allowed to execute.

  1. This is the error I see: The fallback error is thrown every time, even when the mutation is explicitly set to allow.

Expected behavior

The updateManyUserProfiles and updateManyUserPrograms should not throw the fallback error.

Actual behaviour

No matter what we try, the fallback error is always thrown, just for those two mutations.

Additional context

Not sure if we are doing something wrong, if it is some weird naming problem, or if it is something else.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:14

github_iconTop GitHub Comments

1reaction
spencerolsencommented, Oct 18, 2019

I’m sorry I haven’t been able to respond. While I still would like to find a solution for this (and help so that @maticzav can reproduce), we went another direction for now and I haven’t been able to circle around to this. Here is the schema introspection I ran, let me know if you need something different. I will try and create small reproduction repo here in the next week or so.

schema introspection.txt

0reactions
guiaramoscommented, Sep 2, 2020

Any solution?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Two mutations showing as not authorized, but still ... - GitHub
If fallbackRule is set to deny , then mutations, which should be authorised throw Unauthorised after successful completion of their execution.
Read more >
Multiple mutations in a request | Hasura GraphQL Docs
If multiple mutations are part of the same request, they are executed sequentially in a single transaction. If any of the mutations fail,...
Read more >
Setting Up Authentication and Authorization with Apollo ...
Set up Apollo Gateway and an implementing service with a federated schema to manage access to user account data; Sign a JWT for...
Read more >
cURL showing error "Not Authorized/Not Authenticated" - FAQs
Hi. I am new here. I tried to use the CURL example of modifying a column in my board. I copied the V2...
Read more >
Resolve unauth errors for GraphQL requests in AWS AppSync
I receive "Unauthorized" errors when I run GraphQL requests with AWS ... The Authorization or x-api-key header is present and contains the ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found