AlistGo/alist · error

failed to decode jwt token

Error message

failed to decode jwt token

What it means

Thrown by getSub() in the Aliyundrive Open driver when the JWT payload segment cannot be base64-decoded. The driver uses base64.RawStdEncoding.DecodeString on segments[1]; if the payload contains URL-safe characters ('-','_') or padding, standard decoding fails.

Source

Thrown at drivers/aliyundrive_open/util.go:163

	}
	newSub, err := getSub(refresh)
	if err != nil {
		return "", "", err
	}
	if curSub != newSub {
		return "", "", errors.New("failed to refresh token: sub not match")
	}
	return refresh, access, nil
}

func getSub(token string) (string, error) {
	segments := strings.Split(token, ".")
	if len(segments) != 3 {
		return "", errors.New("not a jwt token because of invalid segments")
	}
	bs, err := base64.RawStdEncoding.DecodeString(segments[1])
	if err != nil {
		return "", errors.New("failed to decode jwt token")
	}
	return utils.Json.Get(bs, "sub").ToString(), nil
}

func (d *AliyundriveOpen) refreshToken(ctx context.Context) error {
	if d.ref != nil {
		return d.ref.refreshToken(ctx)
	}
	refresh, access, err := d._refreshToken(ctx)
	for i := 0; i < 3; i++ {
		if err == nil {
			break
		}
		if rateLimitErr, ok := err.(*refreshRateLimitError); ok {
			wait := rateLimitErr.retryAfter
			if wait <= 0 {
				wait = time.Duration(i+1) * 2 * time.Second
			}

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Inspect the token's middle segment manually: echo '<payload>' | base64 -d vs base64 -d with urlsafe translation to confirm the encoding
  2. Regenerate the refresh token via the official OAuth flow so a current, well-formed token is stored
  3. Update the alist driver to a version where getSub handles base64.URL encoding if the provider changed format

Example fix

// before (util.go)
bs, err := base64.RawStdEncoding.DecodeString(segments[1])
// after: tolerate both encodings
seg := strings.NewReplacer("-", "+", "_", "/").Replace(segments[1])
bs, err := base64.RawStdEncoding.DecodeString(seg)
Defensive patterns

Strategy: validation

Validate before calling

func tryDecodeJWTPayload(seg string) ([]byte, error) {
    if bs, err := base64.RawStdEncoding.DecodeString(seg); err == nil { return bs, nil }
    if bs, err := base64.RawURLEncoding.DecodeString(seg); err == nil { return bs, nil }
    return nil, errors.New("undecodable jwt payload")
}

Try / catch

if err != nil && strings.Contains(err.Error(), "failed to decode jwt token") { seg := tokenSeg1; if _, e2 := base64.RawURLEncoding.DecodeString(seg); e2 == nil { /* encoding variant: handle urlsafe */ } }

Prevention

When it happens

Trigger: refreshTokenWithPost calls getSub(d.RefreshToken) or getSub(refresh) where the token's middle segment is base64url-encoded (RFC 7515 style, common for JWS tokens) rather than raw standard base64, or the segment is otherwise malformed/truncated.

Common situations: Aliyun changed or issues tokens signed with a different encoding variant; the token was truncated when copied into storage config; a proxy mangled the token response body.

Understand the failure class

Related errors


AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15). Data as JSON: /api/errors/b7161da4c29fad58. Report an issue: GitHub.