Rails 5 set Authorization header - ruby-on-rails

I got JSON Web Token login going but am in the process of fixing my Rails 5 Controller tests.
I am trying to pass my JWT auth token to my GET request header.
So far, in my User Controller test, I have this test:
test "users should return list of users" do
User.create(#bob)
auth_token = log_in_as(#bob)
request.headers['Authorization'] = "JWT #{auth_token}"
get users_path
assert_response :success
assert_not response.body.empty?
end
So far that doesn't work, I get response not authenticated.
If I change it to like so:
test "users should return list of users" do
User.create(#bob)
auth_token = log_in_as(#bob)
get users_path, nil, { HTTP_AUTHORIZATION: "JWT #{auth_token}" }
puts "response = #{response.body}"
assert_response :success
assert_not response.body.empty?
end
I get this expected response:
response = {"users":[{"id":298486374,"name":"MyString","email":"MyString","cats":[]},{"id":980190962,"name":"MyString","email":"MyString","cats":[]},{"id":980190963,"name":"Bob","email":"bob#gmail.com","cats":[]}]}
but I also get a DEPRECATED WARNING:
DEPRECATION WARNING: ActionDispatch::IntegrationTest HTTP request
methods will accept only the following keyword arguments in future
Rails versions: params, headers, env, xhr
Examples:
get '/profile', params: { id: 1 }, headers: { 'X-Extra-Header' =>
'123' }, env: { 'action_dispatch.custom' => 'custom' }, xhr: true
So what is the recommended way to set HTTP Authorization header in Rails 5 ?

You need to include the params and headers key in the arguments see here.
get users_path, params: {}, headers: { HTTP_AUTHORIZATION: "JWT #{auth_token}" }
You first example probably isn't working because you are setting the JWT on Authorization and not HTTP_AUTHORIZATION.
request.headers['HTTP_AUTHORIZATION'] = "JWT #{auth_token}"

Related

removing authorization from rspec get request

I have a controller in rails such that when i go to the url :
/my-path
it outputs json text.
There is no authorization involved.
When I open the URL in browser or postman i get the expected json data.
I can't test it in rspec as i get a no authorization error.
before do
get base_url , params: {} #, headers: { 'Content-Type' => 'application/x-www-form-urlencoded', Authorization: 'Token: sdaf' }
end
it 'returns 200' do
puts response
expect(response.code).to eq '200'
end
When i do the above, i get the following error :
Failure/Error: expect(response.code).to eq '200'
expected: "200"
got: "401"
Authorization header missing.
I am new to rails, so i have little idea on what i am missing out here.
Hope you are writing your rspec test in the controller test file, in that case if your writing test for say example home_controller, index action explictly specify controller action like below, hope it helps :)
before do
get :index, params: {} #, headers: { 'Content-Type' => 'application/x-www-
form-urlencoded', Authorization: 'Token: sdaf' }
end

Devise test helper fails to sign in

I have a rails API app using devise_token_auth and in my tests (minitest) I need to send POST requests and signed in users so I used the sign_in method but it doesn't seem to be doing anything.
This is my test file
require 'test_helper'
class ActivityControllerTest < ActionDispatch::IntegrationTest
include Devise::Test::IntegrationHelpers
test "post activity" do
sign_in users('one')
post '/activity/', params: {
original_activity_log_file: fixture_file_upload('files/test_gpx.gpx', 'application/gpx'),
title: 'test activity',
description: 'test description'
}
assert_response 200
end
end
And this is the result when run
Expected response to be a <200: OK>, but was a <401: Unauthorized>
Response body: {"errors":["You need to sign in or sign up before continuing."]}.
Expected: 200
Actual: 401
What could be going on here to cause the test to fail?
You're using devise_token_auth in that case plain devise helpers doesn't work, you need perform plain authorization with post request. Here is an example:
# make a request in order to get tokens
post(
api_user_session_path,
params: {
email: "foo#bar.com",
password: "password"
}.to_json,
headers: {
'Content-Type' => 'application/json',
'Accept' => 'application/json'
}
)
# fetch data from response
client = response.headers['client']
token = response.headers['access-token']
expiry = response.headers['expiry']
token_type = response.headers['token-type']
uid = response.headers['uid']
auth_params = {
'access-token' => token,
'client' => client,
'uid' => uid,
'expiry' => expiry,
'token_type' => token_type
}
new_client = users('one')
get(
api_find_client_by_name_path(new_client.name),
headers: auth_params
)
assert_response :ok

How to set the request.body for an Rspec request spec with a GET request

rails 5.0.0.1
rspec 3.5
I have inherited a code base. I am busy writing integration tests to tie down the app functionality before I consider refactoring.
I have the following lines in a controller concern before_action. It seems to read the request body. The json value here is used to extract an identifier used to authenticate the request.
request.body.rewind
body = request.body.read
json = JSON.parse(body) unless body.empty?
I need to test that the authentication happens correctly.
How can I set the request.body for a GET request spec?
I think you should be able to do this via the request env RAW_POST_DATA
get root_path, {}, 'RAW_POST_DATA' => 'raw json string'
request.raw_post # "raw json string"
See:
How to send raw post data in a Rails functional test?
https://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec
#rails_post_5
require "rails_helper"
RSpec.describe "Widget management", :type => :request do
it "creates a Widget and redirects to the Widget's page" do
headers = { "CONTENT_TYPE" => "application/json" }
post "/widgets", :params => '{ "widget": { "name":"My Widget" } }', :headers => headers
expect(response).to redirect_to(assigns(:widget))
end
end
or just
post "/widgets", params: '{ "widget": { "name":"My Widget" } }'

How to pass authentication token in RSpec test for JSON API?

I'm trying to add an authorization token to an RSpec get JSON API test in Rails. But everything tried so far results in an error. The issue seems that the token is not being properly passed in the request.
expected the response to have a success status code (2xx) but it was 401
Current code:
Project_spec.rb (tests)
before do
#project = create(:project, :key => "123")
get '/api/v1/projects/1', {:Authorization => "Token 123"}, format: :json
end
it "returns correct status" do
expect( response ).to have_http_status(:success)
end
ProjectsController.rb
before_filter :restrict_access, :except => :create
def show
#project = Project.find(params[:id])
render json: #project
end
def restrict_access
authenticate_or_request_with_http_token do |token, options|
Project.exists?(key: token)
end
end
Based on a few recommended solution found online, I've tried
get '/api/v1/projects/1', format: :json, token: "123"
get '/api/v1/projects/1', { 'HTTP-AUTHORIZATION' => 'Token "123"' }, format: :json
get '/api/v1/projects/1', {:Authorization => "Token 123"}, format: :json
But nothing seems to successfully pass the authorization token.
Note: Style in #3 works when posting from an external application, but not in the RSpec test itself.
Does anyone have experience with this and can share some direction?
Use it like:
get '/api/v1/projects/1', {}, { Authorization: "Token 123"}
get is the http method, {} an empty params, { :Authorization => "Token 123"} headers
get(path, parameters = nil, headers_or_env = nil)
Documentation
Other way:
before do
# some code here
#request.env['Authorization'] = "Token 123"
get '/api/v1/projects/1', format: :json
end
It worked when I just tried like this
get '/api/v1/projects/1', as: :json, headers: {:Authorization => "Token 123"}

Authorization Token in request header for Rails JSON API DELETE not being recognised

I am putting together a Restful JSON API using rails-api.
I am in the processing of testing my DELETE api/v1/users/:id using rspec. I cannot get it to pass when I use an HTTP token as authentication (for the delete action). I have tested via the terminal and it works but the test wont pass.
Here is the test spec/requests/api/v1/users_spec.rb
describe "DELETE api/v1/users/:id" do
it "deletes the requested user" do
user = FactoryGirl.create(:user)
request_headers = {
'Authorization' => 'Token token="foobar"'
}
delete "api/v1/users/#{user.id}", request_headers
expect(response.status).to eq 204
end
end
The error I get is expect 204 got 401.
In my users_controller.rb I am using this to get the token
before_action :authenticate, only: [ :destroy ]
TOKEN = "foobar"
def destroy
#user = find_user
#user.destroy
head 204
end
private
def authenticate
authenticate_or_request_with_http_token do |token, options|
token == TOKEN
end
end
I have also tried the following for setting the authorisation token in the request_headers
request_headers = {
'HTTP_AUTHORIZATION' => 'Token token="foobar"'
}
Can anyone point out where I am going wrong or point me in the right direction?
This is now solved via this approach:
describe "DELETE api/v1/users/:id" do
let(:auth_headers) {
{ 'AUTHORIZATION' => 'Token token="foobar"' }
}
let(:user) { FactoryGirl.create(:user) }
it "deletes the requested user" do
delete "api/v1/users/#{user.id}", {}, auth_headers
expect(response.status).to eq 204
end
end
Basically the http headers need to be set in the third parameter. The solution above as passing it as the second so it wasnt getting recognised.

Resources