Permission Based Authorization in Graphql using graphql-rp-directive
(2 min read)@baijanstack/graphql-rp-directive is a package published by me. It uses custom directives in order to apply authorization in graphql. We can do field level authorization using permissions and roles.
Usage
- Install the dependency.
npm install @baijanstack/graphql-rp-directive
- Update your typedefs with the necessary directive.
const typedefs = gql`
directive @hasPermission(permissions: [String!]) on FIELD_DEFINITION | OBJECT
# your other typedefs
# ...
`;
- Create your role and permission data.
import {
getAuthorizedSchema,
TRolePermission,
} from "@baijanstack/graphql-rp-directive";
const rolePermissionsData: TRolePermission = {
ADMIN: {
permissions: [
"READ_SECURE_DATA",
"READ_RESTRICTED_FIELD",
"READ_MUTATION_RESPONSE",
"CREATE_FIELD",
],
},
PUBLIC: {
permissions: ["READ_MUTATION_RESPONSE"],
},
};
- Create your executable schema with your typedefs and resolvers.
const schema = makeExecutableSchema({
typeDefs,
resolvers,
});
- Add the permission directives to your schema.
const schemaWithPermissionDirective = getAuthorizedSchema(schema, {
rolePermissionsData,
});
- Pass
schemaWithPermissionDirective
as schema to your graphql server and return theuser
object from the context.
const server = new ApolloServer<{
user: {
roles: Array<string>;
};
}>({
schema: schemaWithPermissionDirective,
context: {
user: {
roles: ["PUBLIC"],
},
},
});
-
By default, all your resolvers request will be denied unless you specify the directive on the field or object.
-
Apply directives to your typedefs.
const typeDefs = `
directive @hasPermission(permissions: [String!]) on FIELD_DEFINITION | OBJECT
type Query {
# this api will be denied request because it is missing the directive
publicFields: PublicField
restrictedFields: RestrictedField @hasPermission(permissions: ["READ_RESTRICTED_FIELD"])
secureFields: SecureField @hasPermission(permissions: ["READ_SECURE_DATA"])
}
type PublicField {
name: String!
}
type RestrictedField {
name: String!
}
type SecureField @hasPermission(permissions: ["READ_SECURE_DATA"]) {
name: String!
email: String!
}
type Mutation {
createFields(id: Int!): MutationResponse! @hasPermission(permissions: ["CREATE_FIELD"])
}
type MutationResponse @hasPermission(permissions: ["READ_MUTATION_RESPONSE"]) {
done: Boolean!
}
`;