janko / rodauth-rails

Rails integration for Rodauth authentication framework
https://github.com/jeremyevans/rodauth
MIT License
571 stars 40 forks source link

Jwt-refresh not working #59

Closed brunoprietog closed 2 years ago

brunoprietog commented 2 years ago

Hello! I am testing this gem for rails. I want to use it for my graphql api and rails views. I enabled the json and jwt features, along with active_sessions, lockout and jwt_refresh.

Then, I tested the endpoint for login and it worked fine.

POST http://localhost:3000/login
Content-Type: application/json

{
    "login": "a@a.a",
    "password": "123456"
}

I get:

HTTP/1.1 200 OK
Authorization: eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MzIxODA1ODEsImlhdCI6MTYzMjE3ODc4MSwibmJmIjoxNjMyMTc4Nzc2LCJhY2NvdW50X2lkIjoxLCJ1bnZlcmlmaWVkX2FjY291bnQiOnRydWUsImFjdGl2ZV9zZXNzaW9uX2lkIjoiTExGYm4wV2JxU2dqSmFkVzVRYk9xbTE2aXh5dkZRQXVnZk9MUjdPbnZWSSIsImF1dGhlbnRpY2F0ZWRfYnkiOlsicGFzc3dvcmQiXX0.DGyhJhxA2p7YYNTC0mNGuylJotSc2hdZGRwCYRAdWcw
Content-Type: application/json

{
  "access_token": "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MzIxODA1ODEsImlhdCI6MTYzMjE3ODc4MSwibmJmIjoxNjMyMTc4Nzc2LCJhY2NvdW50X2lkIjoxLCJ1bnZlcmlmaWVkX2FjY291bnQiOnRydWUsImFjdGl2ZV9zZXNzaW9uX2lkIjoiTExGYm4wV2JxU2dqSmFkVzVRYk9xbTE2aXh5dkZRQXVnZk9MUjdPbnZWSSIsImF1dGhlbnRpY2F0ZWRfYnkiOlsicGFzc3dvcmQiXX0.DGyhJhxA2p7YYNTC0mNGuylJotSc2hdZGRwCYRAdWcw",
  "refresh_token": "1_3_blZz9zqJrey8LRjyI1FVWxqZ05ZJ0guovymO3dzJ-3M",
  "success": "You have been logged in"
}

But using refresh token tells me that the refresh_token is invalid.

POST http://localhost:3000/jwt-refresh
Content-Type: application/json
Authorization: eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MzIxODA1ODEsImlhdCI6MTYzMjE3ODc4MSwibmJmIjoxNjMyMTc4Nzc2LCJhY2NvdW50X2lkIjoxLCJ1bnZlcmlmaWVkX2FjY291bnQiOnRydWUsImFjdGl2ZV9zZXNzaW9uX2lkIjoiTExGYm4wV2JxU2dqSmFkVzVRYk9xbTE2aXh5dkZRQXVnZk9MUjdPbnZWSSIsImF1dGhlbnRpY2F0ZWRfYnkiOlsicGFzc3dvcmQiXX0.DGyhJhxA2p7YYNTC0mNGuylJotSc2hdZGRwCYRAdWcw

{
  "refresh_token": "1_3_blZz9zqJrey8LRjyI1FVWxqZ05ZJ0guovymO3dzJ-3M"
}

I get:

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": "invalid JWT refresh token"
}

What am I doing wrong? Or is it a issue?

Thanks!

janko commented 2 years ago

Hmm, everything looks right, I'm really not sure what is the issue 🤔 It would be very helpful if you could create a minimal Rails app that reproduces the issue.

brunoprietog commented 2 years ago

Thank you for your response!

Here is an example:

Run bin/dev to start the application.

janko commented 2 years ago

Thanks! I tried it, and I get different results when running the HTTP requests you described against the app:

require "http"

http = HTTP.accept(:json)

response = http.post('http://localhost:3000/login', json: { login: "user@example.com", password: "secret" })

data = response.parse(:json)

response = http
  .headers('Authorization' => data.fetch('access_token'))
  .post('http://localhost:3000/jwt-refresh', json: { 'refresh_token' => data.fetch('refresh_token') })

p response.status
p response.parse(:json)
# #<HTTP::Response::Status 200 OK>
# {"refresh_token"=>"1_12_9M0bfvq1AlVydyKH3uKB0SBo4Lk81XSBIJp-hGKX0qc", "access_token"=>"eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MzIyNjYzNjQsImlhdCI6MTYzMjI2NDU2NCwibmJmIjoxNjMyMjY0NTU5LCJhY2NvdW50X2lkIjoxLCJhY3RpdmVfc2Vzc2lvbl9pZCI6IkJ0TTZkeWNtRFd5anVPNVgyQ0dJWXBsLUJ4NlpRaV9tLW1JYXpCSU1ITnciLCJhdXRoZW50aWNhdGVkX2J5IjpbInBhc3N3b3JkIl19.EZyjM8NiAcQ-SlOQrMyCPX0yCbsKDnjc0FkAf3h3HLQ"}

Is it possible you're running this request against an unverified account? When Rodauth fetches the account from the refresh token in the POST /jwt-refresh request, it only searches through verified accounts (here).

brunoprietog commented 2 years ago

Thank you very much! It was indeed that.

Anyway, the verify_account_grace_period feature is enabled, which means that for the first 24 hours it should have given me the refresh_token. During that period, I was able to login through the rails views without problems and with the json api it also worked fine.

What I did now was to verify the account with internal_request. Is there a possibility to fix that and make the refresh token work during the grace period as well?

While doing this I noticed that there are 2 other errors. When the account is not verified and you can't login, it issues a redirect but with a 200 OK, which means it doesn't work with turbo. The same happens with change login when the account is not verified. Do you think you can fix this?

Sorry, I'm a bit of a newbie at this. Let me know if I can try anything to help.

Thank you very much for your help

janko commented 2 years ago

Anyway, the verify_account_grace_period feature is enabled, which means that for the first 24 hours it should have given me the refresh_token. During that period, I was able to login through the rails views without problems and with the json api it also worked fine.

What I did now was to verify the account with internal_request. Is there a possibility to fix that and make the refresh token work during the grace period as well?

That's a good point. I suggest opening a thread on the Rodauth google group to see what the author thinks of that.

While doing this I noticed that there are 2 other errors. When the account is not verified and you can't login, it issues a redirect but with a 200 OK, which means it doesn't work with turbo. The same happens with change login when the account is not verified. Do you think you can fix this?

PR opened – https://github.com/jeremyevans/rodauth/pull/177.

Closing this issue, as these problems aren't related to rodauth-rails, but to Rodauth directly.

brunoprietog commented 2 years ago

@janko Hi, sorry to bother you again. Now that the new version of rodauth is out, refresh-jwt is supposed to work, but I still can't get the refresh token from an unverified account during the grace period. Do you know if anything additional needs to be done from rails? Thanks!

janko commented 2 years ago

Hmm, for me it works now in your sample app. I ran the following script, where I was able to successfully generate a new refresh token for an unverified account:

require "http"

http = HTTP.accept(:json)

response = http.post('http://localhost:3000/create-account', json: {
  login: "user@example.com",
  password: "secret",
  "password-confirm": "secret"
})
data = response.parse(:json)

response = http
  .headers('Authorization' => data.fetch('access_token'))
  .post('http://localhost:3000/jwt-refresh', json: { 'refresh_token' => data.fetch('refresh_token') })

p response.status # 200 OK
p response.parse(:json) # shows new refresh token
brunoprietog commented 2 years ago

Yes, you are right, I found the problem. It happens that in my new application where I am starting to work, I changed the models from account to user. Basically, I changed everything that said user to account i the migrations. Then in the rodauth configuration I put this:

    methods.grep(/_table$/) do |table_method|
      public_send(table_method) { super().to_s.sub('account', 'user').to_sym }
    end

    active_sessions_account_id_column 'user_id'
    jwt_refresh_token_account_id_column 'user_id'

And it didn't work. I went back to the account model and everything is working. I don't know if I missed to define some column or table name.