Authentication
Overview
Section titled “Overview”Quail follows a Bring Your Own Auth approach — it never touches authentication. Here’s how to wire up the built-in Rails 8 authentication generator with Quail.
Start by scaffolding Rails authentication:
bin/rails generate authenticationbin/rails db:migrateController Context
Section titled “Controller Context”Pass the current user into the GraphQL context from your controller:
class GraphqlController < ApplicationController include Quail::ControllerHelpers
def execute result = AppSchema.execute( params[:query], variables: normalize_request_params(params[:variables]), context: { current_user: Current.user }, operation_name: params[:operationName] ) render json: result rescue StandardError => e raise e unless Rails.env.development? handle_error_in_development(e) endendUsing Context in Resolvers
Section titled “Using Context in Resolvers”Access context[:current_user] in custom queries and mutations:
class MyArticles < Quail::Query type [:article], null: false
def resolve context[:current_user].articles endendclass PublishArticle < Quail::Mutation argument :id, ID, required: true
field :article, ArticleResource.graphql_type, null: true field :errors, [String], null: false
def resolve(id:) article = context[:current_user].articles.find(id) article.update!(published_at: Time.current) { article: article, errors: [] } rescue ActiveRecord::RecordNotFound { article: nil, errors: ["Article not found"] } endendActionCable Authentication
Section titled “ActionCable Authentication”Authenticate WebSocket connections for subscriptions using the session cookie:
module ApplicationCable class Connection < ActionCable::Connection::Base identified_by :current_user
def connect self.current_user = find_verified_user end
private
def find_verified_user session = request.session user = User.find_by(id: session[:user_id]) user || reject_unauthorized_connection end endendThen pass the authenticated user through in your GraphQL channel:
class GraphqlChannel < Quail::Channel private
def context_for_subscription { channel: self, current_user: connection.current_user } endendGenerate the custom channel with rails generate quail:channel if you haven’t already.
This pattern works with the default Rails 8 session-based auth. If you use Devise, JWT, or another auth library, adapt the wiring to match — the context plumbing is the same.