lynndylanhurley / devise_token_auth

Token based authentication for Rails JSON APIs. Designed to work with jToker and ng-token-auth.
Do What The F*ck You Want To Public License
3.55k stars 1.14k forks source link

Post sign in current_user is nil. #1404

Open Gooner91 opened 4 years ago

Gooner91 commented 4 years ago

Before I start, I have also gone through a similar issue here #1231 in detail but it seems the root cause of it was CORS missing expose configuration which in my case are present.

Following is the project setup I have: Rails version 5.2.0 Gem Version Devise-Token-Auth: "1.1.2" Redux token auth version "redux-token-auth": "^0.19.0"

Frontend running on: http://localhost:3000 API accepting requests on http://localhost:3001

Cors Config

config.middleware.insert_before 0, Rack::Cors do
      allow do
        origins 'http://localhost:3000'
        resource '*',
        headers: :any,
        methods: [:get, :post, :put, :patch, :delete, :options, :head],
        expose: ['access-token', 'expiry', 'token-type', 'uid', 'client']
      end
end

Devise Token Auth Config config.change_headers_on_each_request = false

Route Config mount_devise_token_auth_for 'User', at: 'auth'

I have just started a reactjs project with rails api as backend. I was able to implement SignUp and SignIn without any issue but when it comes to sending calls via axios to protected routes I am getting 401 response.

{"errors":["You need to sign in or sign up before continuing."]}

Response headers:

Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Expose-Headers: access-token, expiry, token-type, uid, client
Access-Control-Max-Age: 1728000
Cache-Control: no-cache
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Vary: Origin
X-Request-Id: a001b246-507a-4393-a3ac-e8a531d785a4
X-Runtime: 0.482131

Request headers

Accept: application/json, text/plain, */*
Origin: http://localhost:3000
Referer: http://localhost:3000/profile
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36

Rails Stacktrace

Started GET "/api/v1/users/1/profile" for ::1 at 2020-05-17 01:36:35 +0500
Processing by Api::V1::UsersController#profile as HTML
  Parameters: {"id"=>"1"}
Filter chain halted as :authenticate_user! rendered or redirected
Completed 401 Unauthorized in 16ms (Views: 7.4ms | ActiveRecord: 0.0ms)

I can confirm looking at the local storage the access-token and uid are present there and on every page refresh a successful validate_token request is sent with a 200 response. I have further check current_user on the backend is set to nil on the protected route. Could this be related to redux-token-auth package? I assume this npm package takes care of adding access-token to all the subsequent requests. I have spent hours trying to diagnose this issue and go through similar ones. Would really appreciate any help our being pointed to the right direction.

UPDATE Sending request using postman with all the credentials in the headers results in current_user being fetched as expected. Should it be something related to the frontend rather than the api?

MaicolBen commented 4 years ago

So to the same endpoint, with Postman works but with the frontend doesn't. And I guess in both cases you send a valid token. I'd say that something is wrong with what the frontend is sending, did you check all the headers? A cookie or something is breaking the session.

Gooner91 commented 3 years ago

@MaicolBen hi, its been a while since I posted the actual issue. I will need to gather the information I had back then and get back to you on this.

Gooner91 commented 3 years ago

So to the same endpoint, with Postman works but with the frontend doesn't. And I guess in both cases you send a valid token. I'd say that something is wrong with what the frontend is sending, did you check all the headers? A cookie or something is breaking the session.

Its way too late and I apologize for the delay but the issue I faced was that a request when made via axios library was not setting current_user in the back end. Probably because request's auth headers were not being set. I didn't know and still am not sure if we need to somehow configure axios to add auth headers for each request heading to an authenticated route.

For now the work around I did was (found this on one of the other similar issues I cannot find the link to):

const apiClient = axios.create({
  baseURL: 'http://localhost:3001/api/v1'
});

export const authApiClient = () => {
  apiClient.interceptors.request.use(
    (config) => {
      config.headers = {
        ...config.headers,
        'access-token': localStorage.getItem('access-token'),
        'token-type': localStorage.getItem('token-type'),
        'client': localStorage.getItem('client'),
        'expiry': localStorage.getItem('expiry'),
        'uid': localStorage.getItem('uid'),
      };
      return config;
    },
    error => Promise.reject(error)
  )

  return apiClient;
}

I use authApiClient to make requests to protected routes.