Blook

published: 3/13/2019last updated: 4/10/2019

Authentication

*Goal of this chapter

  • Only logged in user can create post

The goal of this chapter is "only logged in user can create post"

*Related official docs part

https://graphql-ruby.org/authorization/overview.html#what-about-authentication

https://graphql-ruby.org/mutations/mutation_authorization.html

Here we can see the gem author commented how to use current_user

class GraphqlController < ApplicationController def execute variables = ensure_hash(params[:variables]) query = params[:query] operation_name = params[:operationName] context = { # Query context goes here, for example: # current_user: current_user, } result = RailsApiGraphqlCrudTutoSchema.execute(query, variables: variables, context: context, operation_name: operation_name) render json: result rescue => e raise e unless Rails.env.development? handle_error_in_development e end
...

Okay let's un comment out it.

class GraphqlController < ApplicationController def execute variables = ensure_hash(params[:variables]) query = params[:query] operation_name = params[:operationName] context = { # Query context goes here, for example: current_user: current_user, } result = RailsApiGraphqlCrudTutoSchema.execute(query, variables: variables, context: context, operation_name: operation_name) render json: result rescue => e raise e unless Rails.env.development? handle_error_in_development e end end

We need to define current_user method!

And I will show you how to use context later in this chapter, please wait!

So, define current_user method like below

class ApplicationController < ActionController::API def current_user # If test situation when user is logged in User.first # If test situation when user is not logged in # nil end # This is actual my current_user method # current_user method depends on the person # def current_user # token = AccessToken.find_token(bearer_token) # if token && !token.expired? # @current_user ||= token.user # end # end end

Modify create_post mutation

Change this

user = User.first post = user.posts.new(title: title, body: body)

to

post = context[:current_user].posts.new(title: title, body: body)

You can use context[:xxxxxxx] like this.

So the entire code is...

module Mutations # inherit Mutations::BaseMutation class CreatePost < Mutations::BaseMutation # Define what type of value to be returned field :post, Types::PostType, null: false # Define what argument this mutation accepts argument :title, String, required: true argument :body, String, required: true def resolve(title:, body:) # you can access current_user in context like this post = context[:current_user].posts.new(title: title, body: body) # Here returns post field, which is defined above. if post.save { post: post, errors: [], } else # Failed save, return the errors to the client { post: nil, errors: post.errors.full_messages } end end end end

Show error message when user is not logged in

https://graphql-ruby.org/mutations/mutation_authorization.html

module Mutations # inherit Mutations::BaseMutation class CreatePost < Mutations::BaseMutation
# https://stackoverflow.com/questions/3701264/passing-a-hash-to-a-function-args-and-its-meaning def ready?(**_args) if !context[:current_user] raise GraphQL::ExecutionError, "You need to login!" else true end end # Define what type of value to be returned field :post, Types::PostType, null: false # Define what argument this mutation accepts argument :title, String, required: true argument :body, String, required: true def resolve(title:, body:) # you can access current_user in context like this post = context[:current_user].posts.new(title: title, body: body) # Here returns post field, which is defined above. if post.save { post: post, errors: [], } else # Failed save, return the errors to the client { post: nil, errors: post.errors.full_messages } end end end end

Let's test it!

1 When there is logged-in user (logged-in user is First User)

2 When user does not log in

Change current_user to nil

class ApplicationController < ActionController::API def current_user # If test situation when user is logged in # User.first # If test situation when user is not logged in nil end
... end

Let's test it!

It works!!