I am writing a little app for my own curiosity, and am having trouble with the sinatra-cors gem not responding with a 200. This causes Chrome to fail the options request (and subsequently not completing the things on the page).
I have the following set in both a Private
Controller, and a Public
controller. The Public
controller handles routes that require no authentication (such as login), and the Private
controller handles routes that require authentication via JWT.
In the Public
controller, I have :
enable :cross_origin
end
before do
response.headers['Access-Control-Allow-Origin'] = '*'
end
# routes...
options '*' do
response.headers['Allow'] = 'GET, PUT, POST, DELETE, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Authorization, X-Requested-With, X-HTTP-Method-Override, Content-Type, Cache-Control, Accept'
response.headers['Access-Control-Allow-Origin'] = '*'
200
end
The paths
in the Public
controller correctly return 200 for its options requests, since CORS is set to allow all domains.
The paths
in the Private
controller fail with a 500, even though the same cors config is specified in the controller.
The difference, is that the Private
controller, has a use JwtAuth
statement at the start of the controller, which is the middleware
that I have defined for using JWT
tokens. When I remove this, the controllers pass the options request successfully.
The JWT middleware
is as follows :
require 'json'
require 'jwt'
class JwtAuth
CONTENT_TYPE = { 'Content-Type' => 'text/plain' }.freeze
def initialize(app)
@app = app
end
# rubocop:disable Metrics/MethodLength
def call(env)
options = { algorithm: 'HS256', iss: 'Jade-Liberty-Backend' }
bearer = env.fetch('HTTP_AUTHORIZATION', '').slice(7..-1)
payload, _header = JWT.decode(bearer, 'thereisnospoon', true, options)
env[:scopes] = payload['scopes']
env[:user] = payload['user']
@app.call env
rescue JWT::DecodeError
[401, CONTENT_TYPE, [Errors::INVALID_TOKEN]]
rescue JWT::ExpiredSignature
[403, CONTENT_TYPE, [Errors::TOKEN_EXPIRED]]
rescue JWT::InvalidIssuerError
[403, CONTENT_TYPE, [Errors::INVALID_ISSUER]]
rescue JWT::InvalidIatError
[403, CONTENT_TYPE, [Errors::INVALID_ISSUED_AT]]
rescue e
[500, CONTENT_TYPE, [Errors::INTERNAL_SERVER_ERROR]]
end
# rubocop:enable Metrics/MethodLength
end
I followed the following to create the middleware: https://auth0.com/blog/ruby-authentication-secure-rack-apps-with-jwt/
I am unsure why adding the middleware causes the options request to fail.
The issue was related to an error in my middleware (Error module was not included in the source, and the default configuration of Rack caused errors not to be displayed)