Server-side authentication using GraphQL + JWT + Ruby on Rails

Sergey Antonov
Flatstack Thoughts
Published in
5 min readJul 23, 2020

--

I want to share with you how I implemented a simple authentication system using GraphQL and JWT in my Ruby on Rails app. This article is intended for those who are already familiar with technologies such as GraphQL and JWT. For beginners, I’ll attach links at the end of the article.

Pre-requirements:

Connect GraphQL to app

By documentation you just should run rails g graphql:install that will mount our app with GraphQL: it generates GraphQL endpoint, adds app/graphql folder with some base objects.

Execution error responder

To build an error message if some action will fail I added concern to app/graphql/concerns folder that uses GraphQL::ExecutionError class from graphql-ruby gem to raising error messages. This class will add the “errors” key to the response that contains the error message, status, code, and location. I included ExecutionErrorResponder into BaseMutation object to use execution_error method in mutations.

1st pic. app/graphql/concerns/execution_error_responder.rb

Below I attached an example of a response with error message:

2nd pic.

User registration mutation

To add the ability to register user, I created Mutations::RegisterUser mutation that takes email, password, and password_confirmation as arguments that looks like as:

3rd pic. app/graphql/mutations/register_user.rb

Method #resolve takes all available attributes that are described in 3–5 lines (3rd pic.) and then we can modify or sanitize these params if needed. Since mutation returns values via fields, we should describe them in this class like in 7–8 lines (3rd pic.). null: false in this case, means that the field always contains the value.

But I wanted to refactor this code a little bit and moved field describing in a separate folder named “payloads”:

4th pic. app/graphql/mutations/register_user.rb
5th pic. app/graphql/types/payloads/register_user_type.rb

For implementing registration logic I used organizer from interactor gem (Users::Register.call(user_params: params) on line 18 in the 4th pic.) that firstly saves new user in the database and then generates JWT for him. I did not use refresh tokens in my case, I am just generating a token that is valid for one day. I will talk about the implementation of the token generation a little later.

To check locally how works registration system I use helpful GUI for editing and testing GraphQL queries and mutations is https://www.electronjs.org/apps/graphiql.

6th pic.

And we receive the next response for the query above:

7th pic.

If registerUser mutation will be failed, I will receive an error message that generates by ExecutionErrorResponder in response:

8th pic.

User login mutation

To log in user, I use almost similar logic to registerUser mutation. But for this case, I permit only required email and password as arguments:

9th pic. app/graphql/mutations/login_user.rb

In the organizer (line 17 on 9th pic.), I first try to find existed user and then generate a token for him. Payload data for this mutation are identical to registerUser:

10th pic. app/graphql/types/payloads/login_user_type.rb

Authentication implementation

I will not go into detail about how the JWT works, as there are a lot of such articles on the Internet. Here I just wanted to show how use GraphQL with JWT technology. As I wrote earlier, I generate a token for each case when a user logs in or signs up. I use common interactor that responsible for this action. You can also use another algorithm for cryptographic signing or add some payload data.

11th pic. app/interactors/users/generate_token.rb

When we have generated token for the user we should authenticate him for each request. To realize this action I wrote some decoder that receives user ID from the token that will be placed in the request header. I wrapped this logic into controller’ concerns:

12th pic. app/controllers/concerns/authenticable_user.rb

GraphQL provides the ability to pass some specific values for the request using context. In my case, to share current_user with GraphQL mutations I used this feature. I just pass current_user in GraphqlController like as:

13th pic. app/controllers/graphql_controller.rb

But that is not all. We also should implement authentication logic on the GraphQL side. I used #ready? method for this that was provided by gem. It allows checking current_user existence before running mutations. I also wrapped this logic into concerns to simply include in each mutation:

14th pic. app/graphql/concerns/authenticable_api_user.rb

The method #ready? will be run before #resolve and if current_user will be nil method will raise an unauthorized error. For example, I tried to create a company as an unauthorized user:

15th pic.

And then an error message:

16th pic.

That’s all it takes to easily implement an authentication system using JWT and GraphQL in Ruby on Rails apps. I will be happy to answer your questions.

Useful links:

https://en.wikipedia.org/wiki/JSON_Web_Token

https://graphql-ruby.org/

https://github.com/jwt/ruby-jwt

https://www.electronjs.org/apps/graphiql

https://jwt.io/introduction/

--

--