Interface TaskAuthorizationProvider
- All Known Implementing Classes:
TestTaskAuthorizationProvider_v0_3
Implementers provide a CDI bean (@ApplicationScoped) implementing this interface
to control which users can read, write, or create tasks. When no implementation is provided,
all operations are permitted.
Providing an implementation
Create an @ApplicationScoped CDI bean that implements this interface. The SDK
automatically discovers it and wires it into the request pipeline — no additional
configuration is required.
@ApplicationScoped
public class MyTaskAuthorizationProvider implements TaskAuthorizationProvider {
@Override
public boolean checkRead(ServerCallContext context, String taskId, TaskOperation op) {
User user = context.getUser();
// look up ownership in your backing store
return isOwner(user, taskId);
}
@Override
public boolean checkWrite(ServerCallContext context, String taskId, TaskOperation op) {
return checkRead(context, taskId, op); // same rule
}
@Override
public boolean checkCreate(ServerCallContext context, TaskOperation op) {
return context.getUser().isAuthenticated();
}
@Override
public boolean isTaskRecorded(String taskId) {
return ownershipStore.contains(taskId);
}
@Override
public void recordOwnership(ServerCallContext context, String taskId, TaskOperation op) {
ownershipStore.put(taskId, context.getUser().getUsername());
}
}
Behavior
When a provider is present, the SDK enforces authorization as follows:
onGetTask,onSubscribeToTask,onGetTaskPushNotificationConfig,onListTaskPushNotificationConfigs— callcheckRead(org.a2aproject.sdk.server.ServerCallContext, java.lang.String, org.a2aproject.sdk.server.auth.TaskOperation)onCancelTask,onCreateTaskPushNotificationConfig,onDeleteTaskPushNotificationConfig— callcheckWrite(org.a2aproject.sdk.server.ServerCallContext, java.lang.String, org.a2aproject.sdk.server.auth.TaskOperation)onMessageSend,onMessageSendStream— callcheckWrite(org.a2aproject.sdk.server.ServerCallContext, java.lang.String, org.a2aproject.sdk.server.auth.TaskOperation)if an existing task ID is provided, otherwise callcheckCreate(org.a2aproject.sdk.server.ServerCallContext, org.a2aproject.sdk.server.auth.TaskOperation); after the delegate returns, callrecordOwnership(org.a2aproject.sdk.server.ServerCallContext, java.lang.String, org.a2aproject.sdk.server.auth.TaskOperation)if a new task was createdonListTasks— filtering is pushed down to theTaskStore, which callscheckRead(org.a2aproject.sdk.server.ServerCallContext, java.lang.String, org.a2aproject.sdk.server.auth.TaskOperation)per task to exclude unauthorized entries
TaskNotFoundError — the caller cannot distinguish
"does not exist" from "not authorized", preventing information leakage.
Thread safety
Implementations must be thread-safe. Methods will be called concurrently from multiple requests.
Ownership recording
recordOwnership(org.a2aproject.sdk.server.ServerCallContext, java.lang.String, org.a2aproject.sdk.server.auth.TaskOperation) is only triggered by onMessageSend and
onMessageSendStream — the methods that can create tasks.
Other methods (onGetTask, onCancelTask, etc.) do not trigger recording.
checkRead(org.a2aproject.sdk.server.ServerCallContext, java.lang.String, org.a2aproject.sdk.server.auth.TaskOperation)/checkWrite(org.a2aproject.sdk.server.ServerCallContext, java.lang.String, org.a2aproject.sdk.server.auth.TaskOperation) may be called for tasks the provider has no ownership
data for (e.g., legacy tasks created before the provider was enabled). For production
deployments, a fail-closed policy is recommended: deny access when no ownership
data exists. An owner == null → allow policy is only appropriate for testing or
single-user deployments. If enabling the provider on an existing deployment, consider a
migration step to backfill ownership for pre-existing tasks.
Common pitfalls
- TOCTOU race on ownership recording: The
isTaskRecorded(java.lang.String)→recordOwnership(org.a2aproject.sdk.server.ServerCallContext, java.lang.String, org.a2aproject.sdk.server.auth.TaskOperation)sequence is not atomic. Two concurrentonMessageSendcalls for the same new task can both seeisTaskRecorded()returnfalseand both callrecordOwnership. Implementations must use atomic-insert patterns (e.g.,ConcurrentMap.putIfAbsent,INSERT ... ON CONFLICT DO NOTHING) so the first writer wins and the second is a harmless no-op. - CDI injection requirement: When task authorization is required, always obtain
RequestHandlerthrough CDI injection. Manual instantiation viaDefaultRequestHandler.create()bypasses theAuthorizationRequestHandlerDecorator.
- See Also:
-
Method Summary
Modifier and TypeMethodDescriptionbooleancheckCreate(ServerCallContext context, TaskOperation operation) Check whether the current user is allowed to create a new task.booleancheckRead(ServerCallContext context, String taskId, TaskOperation operation) Check whether the current user is allowed to read the given task.booleancheckWrite(ServerCallContext context, String taskId, TaskOperation operation) Check whether the current user is allowed to write to the given task.booleanisTaskRecorded(String taskId) Check whether the given task is already known to this provider.voidrecordOwnership(ServerCallContext context, String taskId, TaskOperation operation) Record that the current user owns the given task.
-
Method Details
-
checkRead
boolean checkRead(ServerCallContext context, String taskId, TaskOperation operation) throws A2AError Check whether the current user is allowed to read the given task.- Parameters:
context- the server call context containing the authenticated usertaskId- the task being accessedoperation- which RequestHandler method triggered the check- Returns:
trueto allow,falseto deny- Throws:
A2AError- if the authorization check itself fails
-
checkWrite
boolean checkWrite(ServerCallContext context, String taskId, TaskOperation operation) throws A2AError Check whether the current user is allowed to write to the given task.- Parameters:
context- the server call context containing the authenticated usertaskId- the task being accessedoperation- which RequestHandler method triggered the check- Returns:
trueto allow,falseto deny- Throws:
A2AError- if the authorization check itself fails
-
checkCreate
Check whether the current user is allowed to create a new task.- Parameters:
context- the server call context containing the authenticated useroperation- which RequestHandler method triggered the check- Returns:
trueto allow,falseto deny- Throws:
A2AError- if the authorization check itself fails
-
isTaskRecorded
Check whether the given task is already known to this provider. Used to avoid redundantrecordOwnership(org.a2aproject.sdk.server.ServerCallContext, java.lang.String, org.a2aproject.sdk.server.auth.TaskOperation)calls.- Parameters:
taskId- the task to check- Returns:
trueif ownership has already been recorded for this task- Throws:
A2AError- if the check itself fails
-
recordOwnership
void recordOwnership(ServerCallContext context, String taskId, TaskOperation operation) throws A2AError Record that the current user owns the given task. Called after task creation viaonMessageSendoronMessageSendStream.Must be idempotent. Concurrent requests for the same unrecorded task may both call this method before either completes.
- Parameters:
context- the server call context containing the authenticated usertaskId- the newly created taskoperation- which RequestHandler method triggered the recording- Throws:
A2AError- if recording fails
-