JavaScript Revocable Proxies with Proxy.revocable
This article explains revocable proxies in JavaScript, how they
differ from standard proxies, and how to terminate access to a target
object using the built-in Proxy.revocable() factory method.
You will learn the syntax, the mechanics of proxy revocation, and the
primary use cases for implementing temporary, secure object access.
What is a Revocable Proxy?
In standard JavaScript, a proxy created with
new Proxy(target, handler) remains active for its entire
lifecycle. As long as a reference to the proxy exists, consumers can
interact with the underlying target object through the defined trap
handlers.
A revocable proxy is a specialized proxy instance that can be
explicitly turned off at runtime. Once revoked, the proxy loses its
connection to the target object, and any subsequent attempts to perform
operations on the proxy will immediately throw a
TypeError.
Creating a Revocable Proxy
Instead of using the new operator with the
Proxy constructor, you create a revocable proxy using the
static method Proxy.revocable(target, handler).
Syntax
const { proxy, revoke } = Proxy.revocable(target, handler);Parameters
target: The original object, array, or function you want to wrap.handler: An object containing trap methods (such asget,set, orapply) that define custom behavior for operations performed on the proxy.
Return Value
Proxy.revocable() returns a plain JavaScript object with
two properties:
proxy: The newly created Proxy object.revoke: A function with no arguments that, when called, permanently disables theproxy.
How Termination Works
When you invoke the revoke() function, the runtime
permanently severs the internal link between the proxy and the target
object.
Key behaviors upon revocation include: * Immediate
Deactivation: The proxy stops delegating operations to the
target or executing handler traps. * Exceptions on
Access: Any operation performed on the revoked proxy—such as
reading properties, writing properties, checking in,
deleting properties, or calling it as a function—throws a
TypeError: Cannot perform '[operation]' on a proxy that has been revoked.
* Garbage Collection: Revoking the proxy clears its
internal reference to the target object, allowing the target to be
garbage collected if no other references to it exist. *
Idempotency: Calling revoke() multiple
times has no additional effect; subsequent calls are simply ignored.
Practical Example
The following example demonstrates creating a revocable proxy, reading data from it, and terminating it:
const sensitiveData = {
apiKey: "secret_12345",
environment: "production"
};
// Create the revocable proxy
const { proxy, revoke } = Proxy.revocable(sensitiveData, {
get(target, prop) {
console.log(`Accessing property: ${prop}`);
return target[prop];
}
});
// Normal usage while active
console.log(proxy.apiKey);
// Output:
// Accessing property: apiKey
// secret_12345
// Terminate access
revoke();
// Attempting to access after revocation
try {
console.log(proxy.apiKey);
} catch (error) {
console.error(error.message);
// Output: Cannot perform 'get' on a proxy that has been revoked
}Common Use Cases
1. Temporary Access Control and Sandboxing
When passing sensitive objects or APIs to untrusted third-party
libraries, plugins, or worker threads, you can wrap the capability
inside a revocable proxy. Once the operation or lifecycle hook finishes,
invoking revoke() ensures the third-party code cannot
retain long-term access.
2. Preventing Memory Leaks
Holding a reference to a standard proxy prevents its target from being garbage collected. In long-running applications, revoking unused proxies drops the target reference inside the proxy, helping the JavaScript engine reclaim memory.
3. Session and State Expiration
Revocable proxies are useful for enforcing state expiration, such as invalidating an authentication token object or disabling user session utilities once a user logs out.