Reputation: 41
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;
Upvotes: 4
Views: 2247
Reputation: 31
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
Upvotes: 3
Reputation: 41
I agree that the other answer will work, but you might use allowExternalErrors
in addition to (or rather than) debug
.
See the documentation for an explanation of both.
As stated there:
By default shield ensures no internal data is exposed to client if it was not meant to be. Therefore, all thrown errors during execution resolve in Not Authorised! error message if not otherwise specified using error wrapper. This can be turned off by setting allowExternalErrors option to true.
That means that by default, shield will report a 401 error even in cases where a different error is occurring. That means that you will be led to believe that you have an auth issue when in reality it is something else. Getting an auth error for some other error is probably not a good idea, even on your live site.
So, including the option allowExternalErrors: true
will make your error message more clear:
const permissions = shield({
Query: {
users: allow,
},
Mutation: {
login: allow,
},
},
{
allowExternalErrors: true
});
If need be, you can also set debug
to true in development.
Upvotes: 2
Reputation: 157
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.
Upvotes: 6