nejdetkadir / devise-api

The devise-api gem is a convenient way to add authentication to your Ruby on Rails application using the devise gem. It provides support for access tokens and refresh tokens, which allow you to authenticate API requests and keep the user's session active for a longer period of time on the client side
MIT License
152 stars 22 forks source link

Does token refresh work when the access token has expired? #12

Closed jessefilho closed 1 year ago

jessefilho commented 1 year ago

Hi, I begin to use devise-api and I found it a great gem, thanks.

However, I do not understand how the refresh token works.

My configuration is like suggested, but I do not see any reference for refresh_token expiration: api.refresh_token.expires_in seems be the api.access_token.expires_in to me.

# ==> Configuration for :api
  config.api.configure do |api|

      # Access Token
      # access tokens. Access tokens are the credentials representing the authorization given to an application
      # api.access_token.expires_in = 2.hours
      api.access_token.expires_in = 5.seconds
      api.access_token.expires_in_infinite = ->(_resource_owner) { false }
      api.access_token.generator = ->(_resource_owner) { Devise.friendly_token(60) }

      # Refresh Token
      # Unlike access tokens, refresh tokens have a longer lifespan
      api.refresh_token.enabled = true
      api.refresh_token.expires_in = 1.week
      api.refresh_token.generator = ->(_resource_owner) { Devise.friendly_token(60) }
      api.refresh_token.expires_in_infinite = ->(_resource_owner) { false }

      # Authorization
      api.authorization.key = 'Authorization'
      api.authorization.scheme = 'Bearer'
      api.authorization.location = :both # :header or :params or :both
      api.authorization.params_key = 'access_token'

      # Base classes
      api.base_token_model = 'Devise::Api::Token'
      api.base_controller = '::DeviseController'

      # After successful callbacks
      api.after_successful_sign_in = ->(_resource_owner, _token, _request) { }
      api.after_successful_sign_up = ->(_resource_owner, _token, _request) { }
      api.after_successful_refresh = ->(_resource_owner, _token, _request) { }
      api.after_successful_revoke = ->(_resource_owner, _token, _request) { }

      # Before callbacks
      api.before_sign_in = ->(_params, _request, _resource_class) { }
      api.before_sign_up = ->(_params, _request, _resource_class) { }
      api.before_refresh = ->(_params, _request, _resource_class) { }
      # api.before_revoke = ->(_params, _request, _resource_class) { }
    end

Thus, to test it, I decrese the access_token expiration to 5 seconds, and it got the record at database in the table devise_api_tokens

// users/tokens/sign_in
{
    "refresh_token": "arvMhr-aTiBPqv53N1B3n21B_KsJbnXCdZTDM3E2HxWoVoHihpwy-kMRyzNp",
    "expires_in": 5,
    "token_type": "Bearer",
    "resource_owner": {
        "id": 1,
        "email": "test@test.com",
        "created_at": "2023-03-29T07:27:40.783Z",
        "updated_at": "2023-03-29T07:28:31.340Z"
    },
    "access_token": "q-H4PeyB7PnVAusBsUbs2c1_y8kPb9xPdzUWxzGkTAZ9wcxrEtfTAzB8B9QH"
}

However, when I go to refresh this token , I got "token has expired":

curl --location --request POST 'http://localhost:3000/api/v1/users/tokens/refresh' \
--header 'Authorization: Bearer arvMhr-aTiBPqv53N1B3n21B_KsJbnXCdZTDM3E2HxWoVoHihpwy-kMRyzNp'
// users/tokens/refresh
{
    "error": "expired_token",
    "error_description": [
        "Token has expired"
    ]
}

Finally, It seems to be get the same reference of token expiration than access token. But on your code I found this reference :

image

And now , I am lost. Could someone help me, please?

nejdetkadir commented 1 year ago

Hi @jessefilho , you are right. You can fork the repository and then you can send a PR for closing this issue

jessefilho commented 1 year ago

ty. work in progress @nejdetkadir