Reputation: 10350
In our multi tenant Rails 4.2 app, we would like to define a thread local current_token
for User
model and intend to use it through out the whole app. Here is the how the current_token
is defined:
class User < ActiveRecord::Base
def self.current_token=(token)
Thread.current['current_token'] = token
end
def self.current_token
Thread.current['current_token']
end
end
The token is retrieved with User.current_token
. It is vital to keep User.current_token
thread safe and alive throughout the lifespan of a user session. It is pointed out that the thread local may be cleared up by some web server such as puma
. We would like to get feedback from the community about how sound is the thread local in real production. What kind of problem we should be aware of (and possible solution if there is one).
Upvotes: 3
Views: 1505
Reputation: 106882
Thread.current
per se is secure. The risk of Thread.current
is that you have to use it correctly, because it doesn't reset automatically at the end of a request. Some examples:
Imagine you set a token in Thread.current
in one request and do not set to an other token in the next (perhaps because there was no token in the next request), then the old token will still be available.
Or you plan to nullify Thread.current
at the end of each request to ensure each request starts with a blank Thread.current
. Will happen if a request fails with an exception, does it still get nullified?
It is just error-prone to work with Thread.current
directly and there is the risk of exposing data from one request (one user) to a later request (user) on the same server.
You might want to check the RequestStore gem that internally uses Thread.current
, but warps it with some layers of security.
Upvotes: 6
Reputation: 24551
I've never heard of an issue with puma and thread locals. You might want to use the sentient_user gem since its behavior is very close to what you're describing. The only difference is that instead of keeping around a token, you keep around the whole user.
I will note that this pattern is basically a global variable, so it acts like an unstated parameter to any method that uses it. But it can be nice for auditing, so that it is always available no matter where you need it.
Upvotes: 1