Postgraphile — GraphQL API & PostgreSQL
By: Dorian Machado
Tags: Postgresql, Postgres, Postgraphile, GraphQL, JavaScript

Permissions and Security 🔐

Time to start securing our data, first of all let’s give some permissions to the anonymous and the blog_user roles.

GRANT SELECT ON posts TO anonymous;

GRANT SELECT(id) ON users TO anonymous;

GRANT SELECT(name) ON users TO anonymous; GRANT SELECT, INSERT, UPDATE, DELETE ON posts TO blog_user;

GRANT USAGE, SELECT ON SEQUENCE posts_id_seq TO blog_user;

GRANT SELECT(id) ON users TO blog_user;

GRANT SELECT(name) ON users TO blog_user;

If we test to query again the posts as a guest user with

query {

allPosts {

nodes {

id

userByAuthorId {

name

}

title

content

published

}

}

}

We are able to retrieve the posts again 🎉

But, we need to reach our approach and guaranty that the guest users only can view the “published” posts. We need to restrict the access to those published and own posts. So, we need to make sure users can only be able to modify their own posts.

Which means it’s time to enable the “row level security” of PostgreSQL, but first let’s create this function called “current_user_id”. This function just returns null if no user id is given and otherwise returns the id of the user.

CREATE FUNCTION current_user_id() RETURNS INTEGER AS $$

SELECT NULLIF(current_setting('jwt.claims.user_id', TRUE), '')::INTEGER;

$$ LANGUAGE SQL STABLE; GRANT EXECUTE ON FUNCTION current_user_id() TO anonymous;

GRANT EXECUTE ON FUNCTION current_user_id() TO blog_user;

Now we will enable the “row level security” on the table posts

ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

Then we will create the following policies

CREATE POLICY anonymous_public_posts ON posts FOR SELECT TO anonymous

USING (published=true); CREATE POLICY public_posts ON posts FOR SELECT TO blog_user

USING (published=true or author_id=current_user_id()); CREATE POLICY delete_own_posts ON posts FOR DELETE TO blog_user

USING (author_id = current_user_id());



CREATE POLICY update_own_posts ON posts FOR UPDATE TO blog_user

USING (author_id = current_user_id()); CREATE POLICY insert_own_posts ON posts FOR INSERT TO blog_user

WITH CHECK (author_id = current_user_id());

After query again we can notice that only the “published” post is now displaying.

anonymous only can view the “published” posts

Do you remember our token ? it’s time to use it ⚡️ adding it as a header

Add the header

The name of the header will be “Authorization” and the value will be “Bearer + <Token>” as shown in the print screen and hit “save”.

The token belongs to the user “Jhon | jo@example.com” with ID 4 who is the user we created before invoking the function “SIGNUP”

query{

currentUserId

}

The ID of the current user

Querying the GraphQL again we will notice that the post with ID 3 does not appear because is a Draft (not published) and does not belong to the user with whom we are logged in (“Jhon | jo@example.com” with ID 4)

The post with ID 3 does not appears

If we try to delete a post that doesn’t belongs to the current user we will get an error.

mutation {

deletePostById(input:{id:2}) {

clientMutationId

deletedPostId

}

}

The post ID 3 could not be deleted

Same result if we try to update/modify one post

mutation {

updatePostById(input: {id:3, postPatch: {title: "New Title"}}){

post{

id

title

}

}

}

The post ID 3 could not be updated

Let’s see what happen if we create a new post in draft with the current user

mutation {

createPost(input: {post: {id: 999, title: "My very first post", content: "Once upon a time in", published: false, authorId: 4}}) {

post {

id

title

published

}

}

}

New Post created

Querying again

We can see the new post with ID 999

Also se can update our own post

mutation {

updatePostById(input: {id:999, postPatch: {title: "New Title"}}){

post{

id

title

}

}

}

The post was updated successfully

🎉 Amazing 🎉 now we can develop in record time our API ⚡