I am trying to implement GraphQL API using apollo-server-express. I want to manage permissions by graphql-shield middleware but I am having issues with allowing execution of mutations. My goal is to have JWT based authentication but to allow execution of some queries/mutations to unauthenticated users which is needed for register/login mutations. There for I am using default allow
rule. But when I try to run login mutation, I receive Not Authorised! error. I have no clue why is that. The rule works fine with queries.
Thank you for the answer.
Server
import express from "express";
import cors from "cors";
import { ApolloServer, makeExecutableSchema } from "apollo-server-express";
import config from "./config";
import mockResolver from "./resolvers/mockResolver";
import typeDefs from "./graphql/typeDefs";
import { applyMiddleware } from "graphql-middleware";
import permissions from "./graphql/permissions";
const app = express();
app.use(cors());
const server = new ApolloServer({
schema: applyMiddleware(
makeExecutableSchema({ typeDefs, resolvers: mockResolver }),
permissions
),
playground: true,
introspection: true,
});
server.applyMiddleware({ app, path: "/graphql" });
app.listen(config.PORT, () =>
console.log("Server listening at http://localhost:%s", config.PORT)
);
TypeDefs
import { gql } from "apollo-server";
const typeDefs = gql`
type User {
id: Int!
email: String!
password: String!
}
type LoginResponse {
id: String
email: String
token: String
}
type Query {
user(id: Int!): User
users: [User]
}
type Mutation {
login(email: String!, password: String!): LoginResponse
}
`;
Permissions
import { shield, allow } from "graphql-shield";
const permissions = shield({
Query: {
users: allow,
},
Mutation: {
login: allow,
},
});
export default permissions;
const permissions = shield({
Query: {
users: allow,
},
Mutation: {
login: allow,
},
});
to
const permissions = shield({
Query: {
users: allow,
},
Mutation: {
login: allow,
},
},
{
debug: true
});
and trace to error messages.
Both of the above are correct, but if you want to limit the data that might accidentally get exposed to the client, you could keep both allowExternalErrors: false
and debug: false
and handle this on a case-by-case basis. To accomplish that, you need to return any intentionally created errors instead of throwing them. That way, GraphQL Shield can handle those errors intelligently because it knows that returned errors are intended to filter up to the client.
return new Error('This should make it passed the Shield');
vs
throw new Error('This will return a "Not Authorised!" message')
Per their documentation:
To return custom error messages to your client, you can return error instead of throwing it. This way, Shield knows it's not a bug but rather a design decision under control. Besides returning an error you can also return a string representing a custom error message
https://the-guild.dev/graphql/shield/docs/errors
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With