Graphql-shield: Incorrect Error Being Returned

Created on 8 May 2020  路  5Comments  路  Source: maticzav/graphql-shield

Hey guys, I'm currently trying to integrate graphql-shield into my project which is using type-graphql, inversifyJS and prisma and I'm running into an issue where it seems that no matter what I throw, I get a "Not Authorised!" returned and I'm really not sure why. Relevant Code:

//permissions.ts
const authService = serviceContainer.get(AuthService);

const rules = {
  isAuthenticatedUser: rule()( async (parent, args, context) => {
    const userId = await authService.getUserId(context).catch(err => err);
    return Boolean(userId);
  }),
};

export const permissions = shield({
  Query: {
    me: rules.isAuthenticatedUser
  }
});
// auth-resolver.ts
@Mutation(() => UserResponse)
    async registerUser(@Arg("data") data: RegisterInput): Promise<UserResponse> {
        const { email, password, firstname, lastname } = data;
        const user = await this.authService.register(email, password, firstname, lastname);
        return user;
    }



md5-2148168b3792fdc6f9c30212c312eb08



```javascript
//server.ts
const schema = await buildSchema({
        resolvers: [ AuthResolver, UserResolver ],
        container: serviceContainer,
        emitSchemaFile: path.resolve(__dirname, "./generated-schema.graphql"),
        validate: false,
        dateScalarMode: "timestamp",
    });

    const server = new ApolloServer({
        schema: applyMiddleware(schema, permissions),
        playground: true,
        context: ({ req, res }): Context => ({ 
            req,
            res,
            prisma: serviceContainer.get(PrismaClient),
            container: serviceContainer
         }),
    });

In the above code, I'm only protecting one endpoint me(). When I called the mutation registerUser() with an email that's already been registered (there's a unique constraint on email) it's responding with Not Authorized, instead of the error that should be resolved from Prisma, any ideas on why this might be happening when registerUser() isn't behind the shield?
(Including a link to sample repository incase that helps: https://github.com/tnolan8/typegraphql-api)

kinquestion

Most helpful comment

Hey @darrylyoung 馃憢 ,

Are docs unclear about handling errors? What I'd advise is that you return the error inside your resolver - that's a mechanism shield uses to distinguish server errors from "predictable" patterns so that you don't leak internal structure of the app.

All 5 comments

Believe I've found my issue. When inspecting the output of generateMiddlewareFromSchemaAndRuleTree() I can see that it's applying Middleware to all of my types:

MIDDLEWARE:  {
  Query: { me: [AsyncFunction: middleware] },
  UserResponse: {
    email: { fragments: [], resolve: [AsyncFunction: middleware] },
    firstname: { fragments: [], resolve: [AsyncFunction: middleware] },
    lastname: { fragments: [], resolve: [AsyncFunction: middleware] },
    createdAt: { fragments: [], resolve: [AsyncFunction: middleware] }
  },
  Mutation: {
    registerUser: { fragments: [], resolve: [AsyncFunction: middleware] },
    loginUser: { fragments: [], resolve: [AsyncFunction: middleware] }
  },
  AuthPayload: {
    token: { fragments: [], resolve: [AsyncFunction: middleware] },
    user: { fragments: [], resolve: [AsyncFunction: middleware] }
  }
}

When the middleware is executing for registerUser() it gets to: return await resolve(parent, args, ctx, info) Ln 70 in _generator.ts_. The parent fails to resolve because of the failure on the unique constraint and is then caught in the catch() block. Looks like all I needed was to set { allowExternalErrors: true } when creating the shield, seems to do the trick.

Thanks for following up with your solution, @tnolan8. I'm also using Prisma and was wondering why I was seeing the "Not Authorised!" message, despite having a custom error in my resolver. Adding allowExternalErrors: true fixed it for me, too. Thanks.

Hey @darrylyoung 馃憢 ,

Are docs unclear about handling errors? What I'd advise is that you return the error inside your resolver - that's a mechanism shield uses to distinguish server errors from "predictable" patterns so that you don't leak internal structure of the app.

Hi, @maticzav. 馃憢

Thanks for your message. No, the docs aren't unclear; I just clearly didn't read everything thoroughly enough. Taking another look now, the docs cover all of this well.

Related to the issue I thought I had, I _did_ have an error being thrown in my resolver but all I ever got was "Not Authorised!". I thought this was an issue that I could resolve with allowExternalErrors: true but I see now, looking at the docs again, that this is by design. I'll go back through my error handling and, where necessary, return the errors as opposed to throwing them.

This tool is great, by the way. Thank you very much for your hard work on it. I think one of the reasons I rushed through the docs is because I started a project (with Prisma 2) using an example that was using an old version of this package so I didn't pay much attention to it at first until I realised I needed to update it and add some more rules. 馃槃

馃槀 I see! Awesome! I am glad that you've fixed your issue and that you enjoy the library.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

viztor picture viztor  路  6Comments

OGNeutron picture OGNeutron  路  4Comments

BjoernRave picture BjoernRave  路  5Comments

dogscar picture dogscar  路  6Comments

FluorescentHallucinogen picture FluorescentHallucinogen  路  8Comments