-
Notifications
You must be signed in to change notification settings - Fork 112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(api_key): cache api key and organization #3137
Conversation
5ad4aa9
to
38cec71
Compare
9905414
to
19be581
Compare
I understand the point but I believe loading something as core as I think a good first step would be caching the key for a small period of time. Under "heavy load" it would already save hundreds of db queries to find the key, while not adding much risk. I'd also not try to load ActiveModel from a serialize json. We barely used the The cache is refreshed very often in case something changed, no need to expire cache manually. It's not going to save as many DB queries as your approach but I believe the effort and the risk are so much lower. def authenticate
return unauthorized_error unless auth_token
@current_api_key = Rails.cache.fetch("key-#{auth_token}", expire_in: 2.minutes) do
key = ApiKey.find_by(value: auth_token)
{
'id' => key.id,
'permissions' => key.permissions,
'expires_at' => key.expires_at,
'organization_id' => key.organization_id,
}
end
return unauthorized_error unless current_api_key['id']
# Check expiration or simply admit that key expiration are delayed 2 minutes
@current_organization = Organization.find(current_api_key['organization_id'])
true
end This is an example snippet, we can still expire cache when the key is rotated or deleted. Or worst case scenario, it's delayed 2 minutes. def authorize
# get rid of ApiKey.permit? and use THE SAME way to check permissions
- return if current_api_key.permit?(resource_name, mode)
+ return if Array(current_api_key.dig('permissions', resource_name)), mode)
forbidden_error(code: "#{mode}_action_not_allowed_for_#{resource_name}")
end Updating other usage of def track_api_key_usage
return unless track_api_key_usage?
Rails.cache.write(
- "api_key_last_used_#{current_api_key.id}",
+ "api_key_last_used_#{current_api_key['id']}",
Time.current.iso8601
)
end |
3372d63
to
47c962c
Compare
3e88fcd
to
1b87ace
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love that it can be enabled/disabled per endpoint now 👌
1b87ace
to
09e6886
Compare
Context
This PR is part of a global initiative to improve the performance of the LAGO Rest API.
Today every request made received by the API leads to at least two database queries to authenticate the organization. A first one is fetching the
api_key
using the provided bearer token from the HTTP header, the second one loads the relatedorganization
.As by nature, api_keys and organizations are not update really often, adding a caching strategy could reduce drastically the time consumed authenticating the organization.
Description
This PR changes the authentication mechanism by: