I have a very typical Rails backend with Devise and Devise-JWT. When I make a raw cURL request to the endpoint /users/sign_in
I can see in the headers that it is setting an Authorization header with a token.
When I do the same request on my React frontend (which is on a different port, so cross origin configuration is necessary) the only headers I'm seeing in the result are cache-control and content-type.
Now, I have installed the 'cors' gem. I have created an initializer called config/initializers/cors.rb
and I have put this configuration inside:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource('*',
headers: :any,
expose: ["Authorization"],
methods: :any
)
end
end
Yet when I make the request in my React frontend, I see no Authorization header.
I can see that Rails is responding with a 302 redirect. Is this part of the problem? Do I need to configure devise to stop responding with a 302?
I am utterly lost as to what the problem could be.
If you observe the screenshot that follows, logging in the normal way via plain form login gives me an Authorization header, but if I do it via AJAX there is no header.
This is the frontend (AJAX) code which doesn't give me any Authorization header, only "cache-control" and "content-type":
async function submitLogin(email, password) {
let formData = new FormData();
formData.append("user[email]", email)
formData.append("user[password]", password)
let result = await Axios.post(`${process.env.API_URL}/users/sign_in`, formData, {maxRedirects: 0})
console.log(result)
}
the result:
DISCLAMER: This is not a 100% answer to your question, but it will work for sure!
In the case
devise-jwt
is not mandatory in your project, I would suggest you to follow what I did in my Rails 6 / React template:SessionController
in order to make it responding with the JSON format and returning a JWT:JwtWrapper
inapp/helpers/jwt_wrapper.rb
:Now you'll get your valid JWT in the response body.
Bonus
I suggest you to have a look at the restful-json-api-client package which can handle JWT for you as it look for the
token
attribute in the responses and store and pass it to your requests.It also handle JWT renewal automatically! So when you API replies with a 401 error, if you configure the renewal path, it will tries to renew the JWT. If it succeeded, it will redo the query with the new JWT and it's transparent for your app, otherwise if it fails to renew it, it returns the failure to your app so that you can do something with it like redirecting your user to a login page.
Hopefully this time I'm answering a little bit more to your question.