Explore when singleton-style components are acceptable in Scala security work, and how to avoid turning global secret holders or policy services into hidden trust anchors.
Singleton pattern: A design pattern that ensures only one instance of a component exists and provides a single access path to it.
In Scala, object makes singleton-style construction easy. The security question is not how to create a singleton safely. It is whether the thing you are making globally available should be global at all.
Examples that often become singleton-shaped include:
Some of these can be valid single-instance services. Others become hidden trust anchors that are difficult to replace, test, or review.
A globally accessible security object can create problems such as:
The issue is often not thread safety. It is invisible authority.
If a component owns secrets, authorization policy, or key rotation logic, explicit wiring is usually better than ambient global access:
1trait TokenVerifier:
2 def verify(token: String): Either[String, Claims]
3
4final class ApiService(verifier: TokenVerifier):
5 def handle(token: String): Either[String, Claims] =
6 verifier.verify(token)
This keeps the trust boundary visible and testable.
A singleton can still be acceptable when:
Even then, it is worth asking whether “one instance” and “globally reachable from anywhere” have been conflated.
Sensitive material becomes accessible through an object imported casually across the codebase.
Security decisions are made through hidden singleton access instead of explicit dependency boundaries.
The singleton accumulates mutable caches or flags that affect request behavior in ways that are hard to reason about.
Use Scala singletons carefully in security-sensitive code. They are fine for small stateless helpers, but capabilities involving secrets, trust, or policy are usually safer as explicitly injected services with visible ownership.