ruby 36 lines · 6 steps

JWT authentication as a Rails concern

A reusable concern that decodes a bearer token, loads the current user, and rejects bad tokens with clean JSON errors.

Explained by highlit
1module Authenticatable
2 extend ActiveSupport::Concern
3 
4 included do
5 before_action :authenticate_request!
6 attr_reader :current_user
7 end
8 
9 private
10 
11 def authenticate_request!
12 payload = decode_token(bearer_token)
13 @current_user = User.find(payload[:sub])
14 rescue JWT::ExpiredSignature
15 render json: { error: "Token has expired" }, status: :unauthorized
16 rescue JWT::DecodeError, ActiveRecord::RecordNotFound
17 render json: { error: "Invalid or missing token" }, status: :unauthorized
18 end
19 
20 def bearer_token
21 header = request.headers["Authorization"]
22 raise JWT::DecodeError, "Missing Authorization header" if header.blank?
23 
24 header.split(" ").last
25 end
26 
27 def decode_token(token)
28 decoded, = JWT.decode(
29 token,
30 Rails.application.credentials.jwt_secret,
31 true,
32 algorithm: "HS256"
33 )
34 decoded.deep_symbolize_keys
35 end
36end
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1ActiveSupport::Concern lets you inject callbacks and shared behavior into any controller that includes it.
  2. 2Rescuing specific token exceptions maps failure modes to precise 401 responses instead of leaking stack traces.
  3. 3Memoizing the authenticated user in @current_user gives every action access to who is making the request.

Related explainers

Share this explainer

Here's the card — post it anywhere.

JWT authentication as a Rails concern — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code