Class AuthorizedTasks
Secret (authorization context).
It manages the SecretManagerProvider thread-local: it sets the required secret
before the task runs and always restores the previous one in a finally block,
preventing secrets from leaking across scopes.
Use-case matrix
| Thread | Secret | Method | Notes |
|---|---|---|---|
| Same thread | Same (current) — no switch needed | none — just invoke the method directly | No AuthorizedTasks involvement needed. |
| Same thread | Different (explicit) | executeSafely(task, secret) |
Inline context switch. Previous secret is always restored in finally. |
| Different thread / pool | Same as calling thread (current) | bind(task) → then new Thread(...).start() or executor.submit(...) |
Captures the current secret at bind-time and injects it when the task runs. |
| Different thread / pool | Different (explicit) | bind(task, secret) → then new Thread(...).start() or executor.submit(...) |
Binds an explicit secret to the task. Useful when the child thread must run under a different identity than the calling thread (e.g. a service sending a social notification with its own catalogue credentials while the HTTP thread is running under the end-user token). |
| Different thread — fire-and-forget | Different (explicit) | runAsync(task, secret) |
Convenience shortcut: creates a new Thread, binds the explicit secret,
starts it, and returns the Thread in case the caller needs to
join() it. Equivalent to
new Thread(bind(task, secret)).start(). |
Examples
Case 1 — same thread, inline context switch (different secret)
Secret secret = ContextProvider.get().container().authorizationProvider()
.getSecretForContext(targetContext);
AuthorizedTasks.executeSafely(() -> {
// runs on the current thread with 'secret' active
}, secret);
Case 2 — different thread, propagate the current secret
// bind() captures SecretManagerProvider.get() now (calling thread)
new Thread(AuthorizedTasks.bind(() -> {
// runs on the new thread with the calling thread's secret
})).start();
Case 3 — different thread, explicit (different) secret (bind)
Secret catalogueSecret = Utils.getCatalogueSecret();
new Thread(AuthorizedTasks.bind(() -> {
// runs on the new thread with catalogueSecret active, not the caller's secret
}, catalogueSecret)).start();
Case 4 — different thread, fire-and-forget with explicit secret (runAsync)
Secret catalogueSecret = Utils.getCatalogueSecret();
AuthorizedTasks.runAsync(socialPost, catalogueSecret);
MDC and request ID propagation
bind() — in both variants — propagates only the Secret.
When the task runs on a different thread, the SLF4J MDC and any
InheritableThreadLocal-based request-ID holder are not automatically
available because:
- Logback's
LogbackMDCAdapter(v1.2.x+) uses a plainThreadLocal— MDC is never inherited by child threads. - An
InheritableThreadLocalrequest-ID is inherited bynew Thread(...), but not by pooled threads (created once at pool initialisation, not at task-submission time).
RequestIdProvider and ContextPropagatingExecutorService are introduced.-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionstatic RunnableBinds aRunnabletask to the current authorization context.static Runnablestatic <V> Callable<V>Binds aCallabletask to the current authorization context.static <V> Callable<V>static voidexecuteSafely(Runnable task, Secret secret) Executes aRunnabletask immediately within a specific secret context.static <T> TexecuteSafely(Callable<T> task, Secret secret) Executes aCallabletask immediately within a specific secret context.static Thread
-
Constructor Details
-
AuthorizedTasks
public AuthorizedTasks()
-
-
Method Details
-
bind
Binds aCallabletask to the current authorization context. This method captures the current secret fromSecretManagerProviderand returns a newCallablethat will automatically set that secret before executing the original task and reset it afterward. This is useful for delegating tasks to a different thread or for asynchronous execution while maintaining the correct authorization context. -
bind
Binds aRunnabletask to the current authorization context. Similar to thebind(Callable)method, this captures the current secret and returns a newRunnablethat will set the secret before execution and reset it upon completion. -
bind
Binds aCallabletask to an explicitSecretfor deferred execution on a different thread.Use this variant when the child thread must run under a different identity than the calling thread — for example when a service needs to perform an operation using its own service credentials while the current thread is running under an end-user token.
The returned
Callableis not automatically submitted anywhere; the caller is responsible for handing it to anew Thread(...), anExecutorService, or similar. -
bind
Binds aRunnabletask to an explicitSecretfor deferred execution on a different thread.Use this variant when the child thread must run under a different identity than the calling thread — for example when a service needs to perform an operation using its own service credentials while the current thread is running under an end-user token.
The returned
Runnableis not automatically submitted anywhere; the caller is responsible for handing it to anew Thread(...), anExecutorService, or similar.Example — social post sent with the catalogue's own credentials:
Secret catalogueSecret = Utils.getCatalogueSecret(); new Thread(AuthorizedTasks.bind(socialPost, catalogueSecret)).start(); -
runAsync
Creates a newThread, binds the givenRunnableto the providedSecret, starts it immediately, and returns the thread.This is a convenience shortcut for the common fire-and-forget pattern:
new Thread(AuthorizedTasks.bind(task, secret)).start();The returned
Threadcan be used tojoin()if the caller needs to wait for completion. -
executeSafely
Executes aRunnabletask immediately within a specific secret context. This method temporarily sets a specified secret, executes the task, and then restores the previous secret, guaranteeing that the original secret is always put back in place, even if the task throws an exception. -
executeSafely
-