argoproj/argo-workflows · error

failed to decrypt token: %w

Error message

failed to decrypt token: %w

What it means

The token parsed as JWE, but decrypting its claims with the server's token encryption key (tok.Claims) failed. This means the token was encrypted with a different key (or corrupted). Argo rejects the request because claims cannot be trusted.

Source

Thrown at server/auth/sso/sso.go:434

// match the request scheme and host, but this led to problems when Argo is
// behind a TLS termination proxy, since the redirect URL would have the scheme
// "https" while the request scheme would be "http"
// (see https://github.com/argoproj/argo-workflows/issues/13031).
func isValidFinalRedirectURL(redirect string) bool {
	// Copied from https://github.com/oauth2-proxy/oauth2-proxy/blob/ab448cf38e7c1f0740b3cc2448284775e39d9661/pkg/app/redirect/validator.go#L47
	return strings.HasPrefix(redirect, "/") && !strings.HasPrefix(redirect, "//") && !invalidRedirectRegex.MatchString(redirect)
}

// authorize verifies a bearer token and pulls user information form the claims.
func (s *sso) Authorize(authorization string) (*types.Claims, error) {
	tok, err := jwt.ParseEncrypted(strings.TrimPrefix(authorization, Prefix), []jose.KeyAlgorithm{jose.DIRECT}, []jose.ContentEncryption{jose.A256GCM})
	if err != nil {
		return nil, fmt.Errorf("failed to parse encrypted token: %w", err)
	}

	c := &types.Claims{}
	if err := tok.Claims(s.encryptionKey, c); err != nil {
		return nil, fmt.Errorf("failed to decrypt token: %w", err)
	}

	if err := c.Validate(jwt.Expected{Issuer: issuer}); err != nil {
		return nil, fmt.Errorf("failed to validate claims: %w", err)
	}
	return c, nil
}

func (s *sso) getRedirectURL(r *http.Request) string {
	if s.config.RedirectURL != "" {
		return s.config.RedirectURL
	}

	proto := "http"

	if r.URL.Scheme != "" {
		proto = r.URL.Scheme
	} else if s.secure {

View on GitHub (pinned to 35bff19146)

Solutions

  1. Have users re-authenticate to get tokens encrypted with the current key
  2. Ensure all argo-server replicas share the same token encryption key from the same secret
  3. If the key was rotated, invalidate old sessions and force a fresh SSO login
  4. Verify secret name/key in the SSO config matches the actual k8s secret
Defensive patterns

Strategy: try-catch

Try / catch

claims, err := sso.Authorize(auth)
if err != nil {
    // key mismatch/corruption: force re-login
    return status.Error(codes.Unauthenticated, "session invalid, re-login")
}

Prevention

When it happens

Trigger: sso.Authorize receives a syntactically valid JWE whose content encryption key does not match s.encryptionKey — e.g. the argo-sso secret/token-encryption key was rotated or differs between server replicas, or a token from another cluster is presented.

Common situations: Rotating or recreating the `argo-workflows-sso` secret while users hold old cookies; multiple argo-server instances with mismatched keys (different namespace/secret per instance); copying tokens between dev/staging clusters.

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/fa1f4e302fe1fab8. Report an issue: GitHub.