I'm writing a library to call a third party API so that it can be used by a Rails app. To authenticate, the API initially uses basic auth to return a token which is used for all other requests. Tokens remain valid for 1 hour, and multiple tokens can be fetched, using the same basic auth credentials, without invalidating any others.
Here's a cut-down version of what I've got so far:
# frozen_string_literal: true
require "rest-client"
class AcmeClient
ACME_API_URL = Application.secrets.acme[:url]
ACME_API_KEY = Application.secrets.acme[:key]
ACME_API_SECRET = Application.secrets.acme[:secret]
def health_check
url = ACME_API_URL + "api/health"
token = fetch_token
RestClient.get url, { Authorization: "Bearer #{token}"}
end
private
def fetch_token
url = ACME_API_URL + "/api/token"
response = RestClient::Request.execute(
method: :post,
url: url,
user: ACME_API_KEY,
password: ACME_API_SECRET,
payload: "grant_type=client_credentials"
)
JSON.parse(response.body)["access_token"]
end
end
I've included the health_check
method as an example of the API endpoints available.
Having only used existing gems to call APIs before, I'm not sure what to do with the token that gets returned. I don't want to fetch a new one before each API call since that seems unnecessarily excessive, so I'm guessing it would make sense to store it somewhere.
In this case, would it be best to create an acme_tokens
database table with token
and expires_at
columns, and then check the expiry before each new API call?
Or, since calls to the API will be instigated by user actions in the front end of our Rails app, should I store the token in a session variable?
Thanks in advance!
So, i think you can use rails low-level cache to store token.
Modify your fetch_token
method as below:
def fetch_token
Rails.cache.fetch("#{cache_key_with_version}/my_api_token", expires_in: 1.hour) do
url = ACME_API_URL + "/api/token"
response = RestClient::Request.execute(
method: :post,
url: url,
user: ACME_API_KEY,
password: ACME_API_SECRET,
payload: "grant_type=client_credentials"
)
JSON.parse(response.body)["access_token"]
end
end
It will return your token while cache is alive, and request new one if cache is expired. Also, you need to configure your cache_store in development/production env.