1
mirror of https://github.com/rclone/rclone synced 2024-12-22 13:03:02 +01:00

box: Fixed refresh of tokens with OAuth2.0 and JWT

If you use the authentication method OAuth2.0 with JWT on the Box backend
rclone fails to refresh the token before Box expires it. If this happens
mid-transfer the transfer is aborted. This fix expires the tokens from
Box earlier (2 minutes) than expected.

Fixes #7214
This commit is contained in:
Asela 2023-08-14 10:51:17 +10:00 committed by Nick Craig-Wood
parent 2212b3a12e
commit 603fc68add
3 changed files with 12 additions and 9 deletions

View File

@ -202,7 +202,9 @@ func refreshJWTToken(ctx context.Context, jsonFile string, boxSubType string, na
signingHeaders := getSigningHeaders(boxConfig) signingHeaders := getSigningHeaders(boxConfig)
queryParams := getQueryParams(boxConfig) queryParams := getQueryParams(boxConfig)
client := fshttp.NewClient(ctx) client := fshttp.NewClient(ctx)
err = jwtutil.Config("box", name, tokenURL, *claims, signingHeaders, queryParams, privateKey, m, client) // When using OAuth2.0 with JWT Box appears to expire their tokens earlier than expected.
// To counter this, we manually set the token to expire 2 minutes earlier than expected
err = jwtutil.Config("box", name, tokenURL, *claims, signingHeaders, queryParams, privateKey, m, client, 2*time.Minute)
return err return err
} }

View File

@ -32,7 +32,7 @@ func RandomHex(n int) (string, error) {
} }
// Config configures rclone using JWT // Config configures rclone using JWT
func Config(id, name, url string, claims jwt.Claims, headerParams map[string]interface{}, queryParams map[string]string, privateKey *rsa.PrivateKey, m configmap.Mapper, client *http.Client) (err error) { func Config(id, name, url string, claims jwt.Claims, headerParams map[string]interface{}, queryParams map[string]string, privateKey *rsa.PrivateKey, m configmap.Mapper, client *http.Client, earlyExpire time.Duration) (err error) {
jwtToken := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) jwtToken := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
for key, value := range headerParams { for key, value := range headerParams {
jwtToken.Header[key] = value jwtToken.Header[key] = value
@ -93,7 +93,7 @@ func Config(id, name, url string, claims jwt.Claims, headerParams map[string]int
} }
e := result.ExpiresIn e := result.ExpiresIn
if e != 0 { if e != 0 {
token.Expiry = time.Now().Add(time.Duration(e) * time.Second) token.Expiry = time.Now().Add(time.Duration(e)*time.Second - earlyExpire)
} }
return oauthutil.PutToken(name, m, token, true) return oauthutil.PutToken(name, m, token, true)
} }

View File

@ -18,7 +18,6 @@ import (
"github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs"
"github.com/rclone/rclone/fs/config" "github.com/rclone/rclone/fs/config"
"github.com/rclone/rclone/fs/config/configmap" "github.com/rclone/rclone/fs/config/configmap"
"github.com/rclone/rclone/fs/fserrors"
"github.com/rclone/rclone/fs/fshttp" "github.com/rclone/rclone/fs/fshttp"
"github.com/rclone/rclone/lib/random" "github.com/rclone/rclone/lib/random"
"github.com/skratchdot/open-golang/open" "github.com/skratchdot/open-golang/open"
@ -266,11 +265,13 @@ func (ts *TokenSource) Token() (*oauth2.Token, error) {
if !ts.token.Valid() { if !ts.token.Valid() {
if ts.reReadToken() { if ts.reReadToken() {
changed = true changed = true
} else if ts.token.RefreshToken == "" { } //else if ts.token.RefreshToken == "" {
return nil, fserrors.FatalError( // FIXME need to detect JWT here
fmt.Errorf("token expired and there's no refresh token - manually refresh with \"rclone config reconnect %s:\"", ts.name), // Box authentication OAuth2.0 with JWT does not provide refresh tokens
) // return nil, fserrors.FatalError(
} // fmt.Errorf("token expired and there's no refresh token - manually refresh with \"rclone config reconnect %s:\"", ts.name),
//)
//}
} }
// Make a new token source if required // Make a new token source if required