-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat(webdav): add bearer_token_command for dynamic token acquisition #10917
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat(webdav): add bearer_token_command for dynamic token acquisition #10917
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #10917 +/- ##
==========================================
+ Coverage 90.68% 91.00% +0.31%
==========================================
Files 504 504
Lines 39795 40936 +1141
Branches 3141 3241 +100
==========================================
+ Hits 36087 37252 +1165
- Misses 3042 3047 +5
+ Partials 666 637 -29 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
@GreenHatHG, do you know where rclone stores the token? |
The rclone WebDAV I set up requires no authentication. A Python script is used to simulate WebDAV token functionality, allowing token retrieval via API. Detailed steps are included in the test tutorial—please refer to it. |
Sorry, I am not asking about the setup. I was asking about how rclone stores the token, as you said rclone works similarly above. The biggest issue that I see with this PR is saving/reading the token from the config, so I am wondering what others do. Making |
I’ve looked into the Rclone source code and verified the behavior experimentally. Rclone does not persist the token generated by Source Code Analysis// backend/webdav/webdav.go
// fetch the bearer token and set it if successful
func (f *Fs) fetchAndSetBearerToken() error {
_, err, _ := f.authSingleflight.Do("bearerToken", func() (interface{}, error) {
if len(f.opt.BearerTokenCommand) == 0 {
return nil, nil
}
token, err := f.fetchBearerToken(f.opt.BearerTokenCommand)
if err != nil {
return nil, err
}
f.setBearerToken(token)
return nil, nil
})
return err
}// backend/webdav/webdav.go
func (f *Fs) setBearerToken(token string) {
f.opt.BearerToken = token
f.srv.SetHeader("Authorization", "Bearer "+token)
}In Experimental VerificationI verified this behavior by setting up a test environment where I could intercept the token generation requests. Setup
ExecutionI ran [30/11/25 11:47:14] ╭─jooooody@DESKTOP-35U5SPV ~/webdav-test/rclone
╰─$ rclone --config ./rclone.conf lsd mywebdav:
-1 2025-11-22 12:57:13 -1 dvc
[30/11/25 11:47:28] ╭─jooooody@DESKTOP-35U5SPV ~/webdav-test/rclone
╰─$ rclone --config ./rclone.conf lsd mywebdav:
-1 2025-11-22 12:57:13 -1 dvcResultThe proxy logs showed that rclone requested a new token for every single execution. If Rclone were persisting the token, the second run would have reused the previous token (The token expiration time is set to 50 seconds.). My Implementation for DVCIn my current PR, I have added I am unsure if writing to the config file by default is the best approach. How would you prefer we handle this? Option 1: Follow Rclone (Memory Only)
Option 2: Persist by Default (Current PR behavior)
Option 3: User Configurable |
Code-related
treeverse/dvc-webdav#95
Related Issues
Description
This PR introduces dynamic Bearer Token management for WebDAV remotes via the new
bearer_token_commandconfiguration option. Unlike static token configurations, this feature enables DVC to:.dvc/config.local)Key Enhancements
Dynamic Token Workflow
DVC executes this command on-demand to acquire tokens, eliminating manual token rotation.
Secure Token Lifecycle
Fallback Compatibility
Existing static tokens (via
token = xyzconfig) continue working unchanged. This feature only activates whenbearer_token_commandis set.Issue Resolution
This PR directly addresses the use case described in issue #10689, where users of short-lived OIDC tokens (like those from oidc-agent that expire every 5 minutes) currently need to manually update tokens in
.dvc/config.local. With this implementation, users can now configure:DVC will automatically execute this command whenever a token is needed, eliminating the manual token rotation workflow. This matches the pattern used by tools like rclone that was referenced in the issue discussion.
Testing Instructions
Testing Environment Setup
WebDAV Server (Docker):
docker run --rm -p 9000:8080 -v $(pwd)/data:/data rclone/rclone:latest serve webdav /data --addr :8080Token Fetch Script (
get_token.sh):Proxy Server (proxy.py)
Validation Tests Performed
Run these before DVC operations (see Testing Environment Setup): Start WebDAV Server (Docker), Run Proxy Server (python proxy.py)
Short Token Expiry (5s default):
Ouput example:
Long Token Expiry:
TOKEN_EXPIRY_SECONDS=300(5 minutes)Output example: