Last active
November 13, 2020 01:52
-
-
Save goncalvesjoao/5e5131954a12065ac4c601ecf1b827fe to your computer and use it in GitHub Desktop.
Changes you need to make in order to make Devise use JWT Header Authentication
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Add somewhere to your Devise configuration | |
# "config/initializers/devise.rb" | |
Devise.setup do |config| | |
# ... | |
config.warden do |manager| | |
# Registering your new Strategy | |
manager.strategies.add(:jwt, Devise::Strategies::JsonWebToken) | |
# Adding the new JWT Strategy to the top of Warden's list, | |
# Scoped by what Devise would scope (typically :user) | |
manager.default_strategies(scope: :user).unshift :jwt | |
end | |
# ... | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Add the "https://github.com/jwt/ruby-jwt" gem to your "Gemfile" | |
gem 'jwt' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Add the following code to a view | |
# It will show you an example of how to make a | |
# curl HTTP request with the proper authentication headers. | |
# Be sure to actually use a working route and not "http://localhost:3000/api/v1/yada_yada" | |
<% if user_signed_in? %> | |
curl -X GET --header 'Authorization: Bearer <%= JWTWrapper.encode({ user_id: current_user.id }) %>' 'http://localhost:3000/api/v1/yada_yada' | |
<% end %> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Your actual JWT Strategy | |
# "config/initializers/core_extensions/devise/strategies/json_web_token.rb" | |
module Devise | |
module Strategies | |
class JsonWebToken < Base | |
def valid? | |
bearer_header.present? | |
end | |
def authenticate! | |
return if no_claims_or_no_claimed_user_id | |
success! User.find_by_id claims['user_id'] | |
end | |
protected | |
def bearer_header | |
request.headers['Authorization']&.to_s | |
end | |
def no_claims_or_no_claimed_user_id | |
!claims || !claims.has_key?('user_id') | |
end | |
private | |
def claims | |
strategy, token = bearer_header.split(' ') | |
return nil if (strategy || '').downcase != 'bearer' | |
JWTWrapper.decode(token) rescue nil | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Helper module for you to use on your app and in your Strategy | |
# Don't add "Helper" to its name and rails won't load it has a view helper module. | |
# "app/helpers/jwt_wrapper.rb" | |
module JWTWrapper | |
extend self | |
def encode(payload, expiration = nil) | |
expiration ||= Rails.application.secrets.jwt_expiration_hours | |
payload = payload.dup | |
payload['exp'] = expiration.to_i.hours.from_now.to_i | |
JWT.encode payload, Rails.application.secrets.jwt_secret | |
end | |
def decode(token) | |
begin | |
decoded_token = JWT.decode token, Rails.application.secrets.jwt_secret | |
decoded_token.first | |
rescue | |
nil | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Add somewhere to your secrets yml | |
# "config/secrets.yml" | |
development: | |
# ... | |
jwt_secret: 'super random key' | |
jwt_expiration_hours: 24 | |
# ... | |
production: | |
# ... | |
jwt_secret: 'even more super random key' | |
jwt_expiration_hours: 6 | |
# ... |
I have database login and jwt I want default to be database how I can use JWT without making it default strategy?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, firstly thanks @goncalvesjoao for posting these and the corresponding Medium post. I'm playing around with JWT and devise, and I'm thrilled that someone has put together a strategy that uses warden instead of controller filters. Quick question regarding this though. There are a few bare
rescue
s in the code base, which can sometimes be a risky thing to do. Is there anything that might be worth rescuing that doesn't subclassJWT::DecodeError
? I also recognize that this is primarily a gist to back a medium post, so don't take this as critical of what is mostly just a barebones example.Thanks!