I have the gem devise-jwt
installed. I can perform a login request, and receive an Authorization token in return, but when I try to access a secured endpoint, I receive the message: No verification key available.
blaine@devbox:~/langsite/backend [master] $ curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIwZWNjMmIzNi04ZmZiLTQ2Y2QtYTZkNi1iZGRjZmU4YTQxNmMiLCJzdWIiOiIxIiwic2NwIjoidXNlciIsImF1ZCI6bnVsbCwiaWF0IjoxNjA1ODQ2NjczLCJleHAiOjE2MDU4NzU0NzN9.ZyqvylXeLZbrRM2V2s5qsyHxiGgElng58HwQ8qjOHCU" http://localhost:3001/quiz_sentences.json
{"error":"No verification key available"}
This is what I have in my config/initializers/devise.rb
file:
config.jwt do |jwt|
jwt.secret = Rails.application.credentials.secret_key_jwt
jwt.dispatch_requests = [
['POST', %r{^/users/sign_in$}],
['GET', %r{^/$}]
]
jwt.request_formats = { user: [:json] }
jwt.expiration_time = 8.hours.to_i
end
I can log in just fine and receive an Authorization token:
blaine@devbox:~/langsite/backend [master] $ curl -D - -X POST -d "user[email]=brlafreniere@gmail.com&user[password]=blaine" http://localhost:3001/users/sign_in.json
HTTP/1.1 201 Created
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
Referrer-Policy: strict-origin-when-cross-origin
Location: /
Content-Type: application/json; charset=utf-8
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIwZWNjMmIzNi04ZmZiLTQ2Y2QtYTZkNi1iZGRjZmU4YTQxNmMiLCJzdWIiOiIxIiwic2NwIjoidXNlciIsImF1ZCI6bnVsbCwiaWF0IjoxNjA1ODQ4MDQ2LCJleHAiOjE2MDU4NzY4NDZ9.66Hg_NG3E79-ybC4rJK_XkkSxpLcWHWTlOiw96hyvjg
ETag: W/"cfe36cdecee4080492f63e8c8f0c091b"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: c961fc61-a1b4-49f0-bc16-63f19a0abd22
X-Runtime: 0.279213
Vary: Origin
Transfer-Encoding: chunked
It seems that I have the Authorization header exposed as well:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource('*',
headers: :any,
expose: ["Authorization"],
methods: :any
)
end
end
My user model:
class User < ApplicationRecord
include Devise::JWT::RevocationStrategies::JTIMatcher
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable, :recoverable,
:rememberable, :validatable, :jwt_authenticatable, jwt_revocation_strategy: self
end
I'm pretty much baffled, any help appreciated. Thanks.
TLDR; Confirm jwt.secret
is actually being set
I had this same issue, in my case it was caused because the jwt.secret
was not being read correctly, when starting Puma via systemd
.
config.jwt do |jwt|
jwt.secret = ENV['JWT_SECRET_KEY'] # was blank, only if starting via systemd or other daemon
jwt.dispatch_requests = [
['POST', %r{^/login$}]
]
jwt.revocation_requests = [
['DELETE', %r{^/logout$}]
]
jwt.expiration_time = 2.weeks.to_i
end
For some reason, on the remote server, when launching via systemd
service, env['JWT_SECRET_KEY']
was empty. However, when starting Puma manually, it worked fine.
I found this out, by hard coding a string as the secret. Suddenly it worked.
config.jwt do |jwt|
jwt.secret = "012345678901234567890123456789" # Suddenly worked
jwt.dispatch_requests = [
['POST', %r{^/login$}]
]
jwt.revocation_requests = [
['DELETE', %r{^/logout$}]
]
jwt.expiration_time = 2.weeks.to_i
end
If jwt.secret
is empty, it will still generate an auth token
for whatever reason. Like you this threw me off, as it made me assume my setup was correct.
To test if you're running into a similar issue, temporarily hardcode gibberish as the secret. If that works, then you're on the right track
Obviously you should not hard code the string, but rather look into and confirm that your secret is being fed correctly into the above config.
For me that meant specifying an EnvironmentFile
in the systemd
service configuration which contains key=value
pairs (much like a dotenv
file).