sorry I should be more clear. the schema I have above is not supposed to work. I'm trying to demonstrate something I would like to do. You are correct that it does not work.
For the time being, I have opted to design my own authentication and authorization layer with shield.
here is a demo I have designed, after removing all authorization
and authentication
directives. the code is not great and there is definitely a better way to do the actual whitelisting and check:
// permission.ts
export const permissions = shield(
{
Query: {
"*": allow,
},
Mutation: {
signIn: allow,
signUp: allow,
// posts
createPosts: and(rules.isAuthenticated, rules.createPostAsAuthor),
...
},
},
{
debug: true,
}
);
// rules.ts
// whitelist keys for input
function allowedKeysCheck(input: any, allowedKeys: string[]) {
const inputKeys = Object.keys(input);
const isInputAllowed = inputKeys.every((key) => allowedKeys.includes(key));
return isInputAllowed;
}
// author field MUST be of shape author: { connect: { where: { node: { id: "some-id" } } } }
function authorRestriction(object: any) {
if (!allowedKeysCheck(object, ["author"])) return false;
const author = object.author;
if (!allowedKeysCheck(author, ["connect"])) return false;
const connect = author.connect;
if (!allowedKeysCheck(connect, ["where"])) return false;
const where = connect.where;
if (!allowedKeysCheck(where, ["node"])) return false;
const node = where.node;
if (!allowedKeysCheck(node, ["id"])) return false;
return true;
}
export const createPostAsAuthor = rule("createPostAsAuthor", {
cache: "no_cache",
})((_parent, { input }, ctx) => {
// restrict input to only one post
if (input.length !== 1) return new Error("Invalid input");
// restrict input to only author, title, content, and public
if (!allowedKeysCheck(input[0], ["author", "title", "content", "public"]))
return new Error("Invalid input");
// check author connection is valid
if (!authorRestriction(input[0])) return new Error("Invalid input");
const {
author: {
connect: {
where: {
node: { id },
},
},
},
} = input[0];
// ensure that the author of the post is the same as the authenticated user
if (id !== ctx.authContext.sub) return new Error("Not authorized");
return true;
});
I would much prefer the schema first solution, but for me this will have to work for now.