Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails: Completed 401 Unauthorized

I'm getting this error, but I don't know why. I specifically exclude CSRF checking. The #webhook method works, even in production. Other similar questions are about Devise, but I'm not using Devise in this controller.

stripes_controller.rb
class StripesController < ApplicationController
  Stripe.api_key = ENV['STRIPE_PRIVATE']
  protect_from_forgery :except => [:webhook, :create]
  
  def show
  end

  def create
    # Amount in cents
    @amount = params[:amount]
  
    customer = Stripe::Customer.create(
      :email => params[:stripeEmail],
      :source  => params[:stripeToken]
    )
  
    charge = Stripe::Charge.create(
      :customer    => customer.id,
      :amount      => @amount,
      :description => 'Membership Fee',
      :currency    => 'usd'
    )
  
    render :show
  rescue Stripe::CardError => e
    flash[:error] = e.message
    redirect_to stripe_path
  end
routes.rb
resource :stripe do
Log
Started POST "/stripe/" for 127.0.0.1 at 2018-01-03 11:58:17 -0500
Processing by StripesController#create as HTML
  Parameters: {"amount"=>"100", "stripeToken"=>"tok_1BgFZ2IYOmXNPhc121HxNtw0", "stripeEmail"=>"[email protected]"}
  Rendering stripes/show.haml within layouts/application
  Rendered stripes/show.haml within layouts/application (2.0ms)
  User Load (3.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
   (2.0ms)  BEGIN
   (1.0ms)  COMMIT
Completed 401 Unauthorized in 3533ms (ActiveRecord: 6.0ms)


Started GET "/" for 127.0.0.1 at 2018-01-03 11:58:21 -0500

Rails is by default on :debug log level. http://guides.rubyonrails.org/v5.0/debugging_rails_applications.html#log-levels

I was able to reproduce it by setting

devise.rb
config.timeout_in = 1.minute # 8.hours

It works fine if I am logged in and active, but if the session times out, then it causes this 401 problem.

This is the request/response from the browser. It shows a success and 302 response, not 401. It says 401 in the server console log though.

POST /stripe/ HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Content-Length: 82
Cache-Control: max-age=0
Origin: http://localhost:3000
Content-Type: application/x-www-form-urlencoded
...

HTTP/1.1 302 Found
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Location: http://localhost:3000/
Content-Type: text/html; charset=utf-8

There isn't a single 401 response in the browser network log, even sorted by status, even with Preserver Log.

Rails 5.0.2

like image 918
Chloe Avatar asked Dec 23 '22 11:12

Chloe


2 Answers

HTTP code 401 Unauthorized is for authentication (https://httpstatuses.com/401). It is not related to CSRF. In that case it would raise ActionController::InvalidAuthenticityToken.

I'am pretty sure you have a before_action in your ApplicationController that requires user authentication (or in routes.rb, or in the config of nginx/Apache).

like image 67
Alexis Avatar answered Jan 09 '23 14:01

Alexis


I tracked the problem down to user_signed_in? as suggested by Marek. That function will HALT execution and issue a 302 redirect, while printing a 401 in the server log!

devise.rb
config.timeout_in = 1.minute # 8.hours
stripes_controller.rb
class StripesController < ApplicationController
  layout false
show.haml
%h2 Thank you!
%p 
  Your payment of 
  %strong= number_to_currency(@amount.to_i * 0.01)
  has been received.
- if user_signed_in?
  Signed in
- else
  Signed out
  

If the user is signed in, the page will load fine. If the user's session expires, then Devise will redirect and set a flash message!

log
Started GET "/stripe" for 127.0.0.1 at 2018-01-03 14:39:08 -0500
Processing by StripesController#show as HTML
  Rendering stripes/show.haml
  User Load (22.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
   (1.0ms)  BEGIN
   (2.0ms)  COMMIT
  Rendered stripes/show.haml (179.2ms)
Completed 401 Unauthorized in 399ms (ActiveRecord: 52.0ms)


Started GET "/stripe" for 127.0.0.1 at 2018-01-03 14:39:09 -0500
Processing by StripesController#show as HTML
  Rendering stripes/show.haml
  Rendered stripes/show.haml (2.0ms)
Completed 200 OK in 219ms (Views: 99.8ms | ActiveRecord: 0.0ms)

chrome network log

I couldn't find a way to check if the user is logged in without redirecting.

https://duckduckgo.com/?q=rails+devise+%22user_signed_in%22+stop+redirecting&ia=qa

user_signed_in? isn't even in the Devise API documentation when you search the methods! I was hoping there was an optional argument.

http://www.rubydoc.info/github/plataformatec/devise/Devise

So I set layout false so it stops using application.haml which contains user_signed_in?. I wish there was a better way.

like image 25
Chloe Avatar answered Jan 09 '23 16:01

Chloe