{"record":{"id":"fa1f4e302fe1fab8","repo":"argoproj/argo-workflows","slug":"failed-to-decrypt-token-w","errorCode":null,"errorMessage":"failed to decrypt token: %w","messagePattern":"failed to decrypt token: %w","errorType":"exception","errorClass":null,"httpStatus":401,"severity":"error","filePath":"server/auth/sso/sso.go","lineNumber":434,"sourceCode":"// match the request scheme and host, but this led to problems when Argo is\n// behind a TLS termination proxy, since the redirect URL would have the scheme\n// \"https\" while the request scheme would be \"http\"\n// (see https://github.com/argoproj/argo-workflows/issues/13031).\nfunc isValidFinalRedirectURL(redirect string) bool {\n\t// Copied from https://github.com/oauth2-proxy/oauth2-proxy/blob/ab448cf38e7c1f0740b3cc2448284775e39d9661/pkg/app/redirect/validator.go#L47\n\treturn strings.HasPrefix(redirect, \"/\") && !strings.HasPrefix(redirect, \"//\") && !invalidRedirectRegex.MatchString(redirect)\n}\n\n// authorize verifies a bearer token and pulls user information form the claims.\nfunc (s *sso) Authorize(authorization string) (*types.Claims, error) {\n\ttok, err := jwt.ParseEncrypted(strings.TrimPrefix(authorization, Prefix), []jose.KeyAlgorithm{jose.DIRECT}, []jose.ContentEncryption{jose.A256GCM})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse encrypted token: %w\", err)\n\t}\n\n\tc := &types.Claims{}\n\tif err := tok.Claims(s.encryptionKey, c); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decrypt token: %w\", err)\n\t}\n\n\tif err := c.Validate(jwt.Expected{Issuer: issuer}); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to validate claims: %w\", err)\n\t}\n\treturn c, nil\n}\n\nfunc (s *sso) getRedirectURL(r *http.Request) string {\n\tif s.config.RedirectURL != \"\" {\n\t\treturn s.config.RedirectURL\n\t}\n\n\tproto := \"http\"\n\n\tif r.URL.Scheme != \"\" {\n\t\tproto = r.URL.Scheme\n\t} else if s.secure {","sourceCodeStart":416,"sourceCodeEnd":452,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/server/auth/sso/sso.go#L416-L452","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Have users re-authenticate to get tokens encrypted with the current key","Ensure all argo-server replicas share the same token encryption key from the same secret","If the key was rotated, invalidate old sessions and force a fresh SSO login","Verify secret name/key in the SSO config matches the actual k8s secret"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"claims, err := sso.Authorize(auth)\nif err != nil {\n    // key mismatch/corruption: force re-login\n    return status.Error(codes.Unauthenticated, \"session invalid, re-login\")\n}","preventionTips":["Keep the token encryption key stable; treat rotation as a session-breaking event","Ensure all replicas mount the same secret","Never copy tokens between environments","Document key rotation runbooks for users"],"tags":["jwt","decryption","sso","key-rotation"],"backgroundTag":"token-decryption-key-mismatch","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}