Summary

  • A WebDAV lock token is a unique, server-generated identifier for one lock. Submitting it in the If header demonstrates token knowledge; it does not authenticate the sender, grant write privilege or guarantee that the lock still exists.
  • A valid mutation is a chain of separate decisions: authenticate the principal, authorize the method, resolve every affected resource, submit all required tokens, evaluate tagged or untagged conditions, match the principal to the lock creator or an authorized override, and commit against current state.
  • Collection depth, shared locks, COPY/MOVE and server-chosen timeouts make a token unsafe as a portable lease. The sound control design treats it as bounded coordination evidence and preserves independent authorization and audit records.

The request that did everything right — except earn permission

Imagine a document service with a live exclusive write lock. The editor refreshes its lock, receives a successful response, and later sends a PUT containing the exact token. The server finds that token in the WebDAV If request field. The resource is inside the lock's scope. The state list evaluates to true.

The server returns 403.

An incident review can easily call that a broken lock service. The token matched, so why did the write fail? RFC 4918 gives a precise answer. When a locked resource is modified, the server must check that the authenticated principal matches the creator of the lock in addition to checking valid token submission. Holding a lock also does not confer full privilege to modify the resource. Normal authentication and privilege mechanisms still apply.

Perhaps the editor refreshed the lock under one session and attempted the PUT after changing accounts. Perhaps an administrator removed its write privilege while leaving the coordination state intact. Perhaps the resource moved into a collection whose policy forbids the method. In each case, the lock system can be correct and the denial can be correct.

The token answers one question: which lock does this request know about? It does not answer who is speaking, what that principal may do, whether the requested change is still conditionally valid, or whether every resource touched by the operation is available. Conflating those questions turns a useful collision-avoidance mechanism into an accidental bearer-right system.

What the server actually created

WebDAV extended HTTP for remote authoring: properties, collections, namespace operations and locking. The locking model primarily addresses the lost-update problem, where one writer unknowingly replaces another writer's change. It does not attempt to define ownership of a document or the business validity of an edit.

Each lock has exactly one unique token generated by the server. A client must not interpret the token. RFC 4918 requires token URIs to be unique across resources and time so a submitted value cannot be confused with another lock. When a LOCK creates a new lock, the server returns the token in the Lock-Token response field and in the response body.

That strong uniqueness requirement can sound like a security grant. It is not. A unique identifier lets the server refer to the right coordination record. It does not establish the authority of the party carrying it. RFC 4918 permits servers to expose active lock information through the DAV:lockdiscovery property and explicitly rejects reliance on token obscurity for write access.

The specification recommends UUID URNs as one way to generate unique values, while retaining the permanent opaquelocktoken URI scheme and allowing any unique URI. The current UUID specification, RFC 9562, recommends cryptographically secure randomness when unguessability matters. Even a perfectly random UUID remains an identifier. Entropy can reduce guessing; it cannot decide whether the authenticated principal has DAV:write-content or whether a collection binding may be changed.

This is a fundamental infrastructure distinction:

  • uniqueness prevents two locks from being mistaken for one another;
  • unguessability can reduce unauthorized discovery;
  • possession demonstrates knowledge of a value;
  • authentication binds a request to a principal;
  • authorization decides which action that principal may take;
  • the commit path decides whether current state still permits the action.

Only the first three are properties associated with the token itself, and the third may be weak because lock discovery can expose it.

A lock coordinates; it does not own

RFC 4918 calls the creator of a lock special, but bounded. The creator can use the lock when modifying the resource, subject to ordinary privileges. A server may also allow an administrator, resource owner or other privileged principal to destroy a lock. RFC 3744 supplies an access-control vocabulary that makes these boundaries clearer.

DAV:write-content governs modification of existing resource content. DAV:write-properties governs dead properties. DAV:bind governs adding a member to a collection, including a PUT to an unmapped URI. DAV:unlock governs UNLOCK by a principal other than the lock owner. These privileges can be aggregated under a wider write privilege, but they remain logically distinct from presenting a lock token.

That distinction protects both directions. A user with write privilege cannot ignore a lock established by another editor. A user with a token cannot use it to escape an ACL. An administrator with override authority can remove an abandoned lock without pretending to be its creator. The mechanism remains useful because it does not have to carry all three roles.

Treating the token as ownership produces bad recovery behavior. If an old client process retains a token after a session transfer, a bearer-right design lets yesterday's process write as today's owner. If tokens appear in logs, property reports or support tickets, a bearer-right design converts ordinary diagnostic exposure into control. If a business relationship changes, administrators become afraid to repair stale locks because the token is imagined as title rather than coordination state.

The standard avoids this trap. The server authenticates the principal and checks normal privileges every time.

If is both a condition and a submission channel

The WebDAV If field is easy to misread because it performs two related but distinct functions.

First, it expresses conditions over state tokens and entity tags. Conditions inside one state list are combined with logical AND. Alternative lists are combined with OR. Not negates the condition that follows. An untagged list applies to the Request-URI; a tagged list names the resource to which its conditions apply.

Second, appearance of a lock token in If submits that token to the server. Submission records that the client knows the token required for an affected resource. RFC 4918 deliberately makes this notion independent of the particular list the server evaluates as true. A client can include several alternative lists, and a token in a non-selected list can still have been submitted.

This prevents a subtle mistake in tooling. A gateway that parses If as an ordinary Boolean expression might retain only the winning branch. The WebDAV server could then lose evidence that the request submitted a required token for another affected resource. Conversely, an audit log that records “token present” but not the evaluated list can make a failed entity-tag condition look like a successful precondition.

The two principal failures also differ. If the If condition evaluates false, the method fails with 412 Precondition Failed, after authorization checks. If the operation affects a locked resource but the request did not submit the required token, the server uses 423 Locked with the lock-token-submitted precondition. A 412 says the asserted state condition did not hold. A 423 can say the request lacked the lock evidence it needed. Neither means “the user definitely had no rights,” and neither should be collapsed into a generic lock error.

Lock-Token itself is narrower than its name suggests. A successful new LOCK returns it as a response field. An UNLOCK request uses it to identify the lock to remove. PUT, PROPPATCH, COPY, MOVE and DELETE submit relevant state tokens through If, not by treating Lock-Token as a universal authorization header.

The resource you named may not be the whole operation

A simple mental model imagines one URL, one lock and one token. WebDAV namespace operations make that insufficient.

A lock has a root URL, scope, type and depth. A direct lock originates at its root. A depth-infinity lock on a collection also applies indirectly to descendants, including members added later. A request aimed at one child can therefore be constrained by a lock created higher in the collection hierarchy.

LOCK accepts depth zero or infinity and defaults to infinity. If a server attempts to lock a collection hierarchy and encounters an incompatible lock, it must not leave a partially locked tree. The operation is all-or-nothing within the specified scope, and a Multi-Status response can identify the resource that prevented completion.

The same scope issue appears in ordinary mutations. Deleting a member changes both the member and collection membership. COPY and MOVE have a source and destination. Overwriting a destination can affect existing state. RFC 4918 requires the applicable tokens for all resources that must be unlocked for the operation, not just the value associated with the Request-URI.

MOVE exposes the portability error most clearly. A direct lock does not travel with a resource to its new URL. The resource can leave the scope of an indirect collection lock at the source and enter the scope of a different depth-infinity lock at the destination. A token that was relevant before the move is not a portable lease attached to the content. Its meaning depends on current namespace mappings and lock scope.

This is why authorization and token validation need the complete affected-resource set. A front-end that checks only the visible URL can approve a request that the WebDAV repository must reject. A policy engine that receives only one token and one path cannot accurately decide an operation that changes two collection memberships and overwrites a locked destination.

Shared locks are not one shared password

An exclusive lock conflicts with another write lock of the same type. A shared lock permits compatible shared locks, allowing applications to coordinate through an agreed convention. Every successful shared LOCK still creates a separate lock with its own unique token.

That means three collaborators do not hold one group token. They hold three distinct coordination records. Refreshing one shared lock does not refresh the others. Removing one token with UNLOCK does not guarantee that the resource is now free; the other shared locks remain, and an indirect collection lock may also apply.

Shared locks therefore require an application-level rule. The protocol tells the server which locks exist and which tokens a request submitted. It does not define how a team merges edits, elects a reviewer or resolves a semantic conflict. Calling the lock “shared” does not create a governance body or majority decision. It only changes lock compatibility.

Operational interfaces should preserve this plurality. A dashboard that displays one “locked/unlocked” Boolean hides which principals created which locks, whether they are direct or indirect, when each expires and what an UNLOCK actually removed.

Timeout is a negotiated suggestion with a server decision

Locks can have limited lifetimes so abandoned clients do not block work forever. A client may suggest a value in the Timeout request field when creating or refreshing a lock. The server chooses the actual timeout and can ignore or change the suggestion.

A refresh is a bodyless LOCK request containing one lock token in If. The server ignores Depth for the refresh, resets the timer if the refresh succeeds, leaves sibling shared locks unchanged, and returns updated DAV:lockdiscovery data. It does not return a new Lock-Token response field.

This protocol is deliberately not a hard lease guarantee. A client must not assume a failed refresh succeeded. It should not conclude that the lock remains alive merely because its locally calculated expiry time is still in the future: a privileged override, server failure or state loss may have removed it. Nor should it assume that the server removed the lock at the exact instant the local timer reached zero without observing current server state.

The safe client behaves as if timeout is a renewal obligation and a hint about likely state. Before a consequential commit it still submits the token and lets the server decide against current lock data. The safe server returns and logs the actual timeout it chose, attributes refreshes, and detects clock or persistence failures that can orphan or prematurely remove locks.

The lock model has a defined edge

WebDAV locks address collision avoidance within operations that honor the repository's lock state. They cannot stop a storage administrator from editing files underneath the server, a separate application from bypassing the repository, or an attacker from compromising the authorization system. They do not guarantee a business transaction, prevent deadlock among several application resources or merge two valid edits.

The protocol also does not mandate locking support for every WebDAV resource. Capability discovery tells a client which forms the server advertises. A client that assumes locking because one endpoint accepted LOCK can still fail on another resource or with another scope.

Those limits are a design strength. A narrow common mechanism is testable. It names a lock, exposes scope, coordinates token submission and provides explicit failure semantics. Applications remain responsible for business rules, identity, privilege, merge policy, storage integrity and recovery.

Heng Lu's distinction between record and authority applies exactly here. A coordination record can be accurate and useful without becoming sovereign. The lock token should describe the state the server created, not acquire the right to command the server. Running code requires a small interoperable contract; future decisions beyond that minimum remain local to the systems that bear the loss.

A defensible write path

A high-assurance WebDAV mutation should make the gates visible rather than compress them into “token accepted.”

  1. Authenticate the principal and bind the request to a session or credential context.
  2. Authorize the exact method and kind of change, including content, properties, collection membership or administrative unlock.
  3. Resolve the Request-URI, destination and every resource whose namespace or state will change.
  4. Discover applicable direct, indirect, exclusive and shared locks at current state.
  5. Parse tagged and untagged If lists, entity tags, negation and alternatives without discarding submitted-token evidence.
  6. Confirm that every required token was submitted and maps to a current lock covering the relevant resource.
  7. Match the authenticated principal to the lock creator, or prove a separately authorized override.
  8. Recheck state at commit, perform the method atomically to the extent the method specifies, and return a precise status or Multi-Status body.
  9. Retain an audit record that can distinguish denied privilege, failed condition, missing token, vanished lock and multi-resource conflict.

This record need not expose the raw token broadly. A keyed fingerprint can correlate requests and lock state while reducing accidental reuse from logs. Audit data should include the principal, method, affected-resource set, lock roots and depths, evaluated condition result, privilege decision, actual timeout, resulting version and response code.

Tests that keep the boundary real

  • Create a lock as one principal, submit its token as another principal and require denial unless an explicit override applies.
  • Grant write privilege without the token and require 423 on a locked affected resource.
  • Submit the token with a failing ETag and require 412 rather than a generic lock failure.
  • Place required tokens in different alternative If lists and verify that submission and Boolean evaluation are both preserved.
  • Create a depth-infinity collection lock, add a new member and verify the indirect lock applies.
  • Attempt a hierarchy lock with one incompatible descendant and prove no partial lock remains.
  • MOVE a directly locked resource and prove the direct lock does not travel, while destination collection locks do apply.
  • Create several shared locks, refresh and remove one, and confirm sibling locks remain unchanged.
  • Request a long timeout, record the server's chosen value, interrupt refresh and verify the client does not assume success.
  • Remove a lock through a privileged path and ensure the event is independently attributed and reviewable.
  • Exercise a direct-storage or alternate-API path and prove it cannot silently bypass the same coordination and audit policy.

These tests assign meaning to the implementation. A standards-compliant parser is necessary, but the security property lives in the complete decision path.

Sources