Server-side authentication using GraphQL + JWT + Ruby on Rails
source link: https://medium.flatstack.com/server-side-authentication-using-graphql-jwt-ruby-on-rails-8820e0471ed4
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
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.
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
BaseMutation object to use
execution_error method in mutations.
Below I attached an example of a response with error message:
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:
#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”:
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.
And we receive the next response for the query above:
registerUser mutation will be failed, I will receive an error message that generates by
ExecutionErrorResponder in response:
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:
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
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.
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:
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
GraphqlController like as:
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:
#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:
And then an error message:
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.
Aggregate valuable and interesting links.
Joyk means Joy of geeK