dotnet/aspnetcore · error · AntiforgeryValidationException

The antiforgery token could not be decrypted.

Error message

The antiforgery token could not be decrypted.

What it means

Thrown by the antiforgery token deserializer when the supplied token bytes cannot be deserialized for any reason (format, version, crypto, length). The serializer deliberately swallows and homogenizes the underlying exception into a single AntiforgeryValidationException to avoid leaking why decryption failed.

Solutions

  1. Persist and share DataProtection keys across all instances (configure AddDataProtection().PersistKeysToFileSystem/Redis with the same key ring and application discriminator).
  2. Verify all nodes in the farm share the same antiforgery application name (AntiforgeryOptions or ApplicationDiscriminator).
  3. Clear the stale antiforgery cookie on the client and obtain a fresh token from the server.
  4. If crossing app versions/migrations, force a token refresh by rotating the data-protection keys.

Example fix

// before: ephemeral keys per instance
builder.Services.AddDataProtection();

// after: shared persistent key ring across the farm
builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo("/shared/keys"))
    .SetApplicationName("MyApp");
Defensive patterns

Strategy: try-catch

Try / catch

try { await antiforgery.ValidateRequestAsync(httpContext); }
catch (AntiforgeryValidationException ex) when (ex.InnerException != null) { logger.LogWarning("Token decryption failed; possible key ring mismatch"); return Results.BadRequest(); }

Prevention

When it happens

Trigger: GetRequestTokensAsync returns a request or cookie token string whose base64-decoded bytes do not deserialize into a valid AntiforgeryToken — e.g. tampered token, stale token from a previous app version, machine key mismatch across farm nodes, or a token issued under different data-protection keys.

Common situations: Deploying to a web farm without shared DataProtection keys; an app restart that lost ephemeral keys (no persistent key ring); token issued by an older incompatible version; client-side manipulation of the cookie; multiple apps sharing the same cookie domain with different keys.

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/3fe2a5e679a970a4. Report an issue: GitHub.

Appendix: source

Thrown at src/Antiforgery/src/Internal/DefaultAntiforgeryTokenSerializer.cs:86

                    return token;
                }
            }
        }
        catch (Exception ex)
        {
            // swallow all exceptions - homogenize error if something went wrong
            innerException = ex;
        }
        finally
        {
            if (tokenBytesRent is not null)
            {
                ArrayPool<byte>.Shared.Return(tokenBytesRent);
            }
        }

        // if we reached this point, something went wrong deserializing
        throw new AntiforgeryValidationException(Resources.AntiforgeryToken_DeserializationFailed, innerException);
    }

    /* The serialized format of the anti-XSRF token is as follows:
     * Version: 1 byte integer
     * SecurityToken: 16 byte binary blob
     * IsCookieToken: 1 byte Boolean
     * [if IsCookieToken != true]
     *   +- IsClaimsBased: 1 byte Boolean
     *   |  [if IsClaimsBased = true]
     *   |    `- ClaimUid: 32 byte binary blob
     *   |  [if IsClaimsBased = false]
     *   |    `- Username: UTF-8 string with 7-bit integer length prefix
     *   `- AdditionalData: UTF-8 string with 7-bit integer length prefix
     */
    private static AntiforgeryToken? Deserialize(ReadOnlySpan<byte> tokenBytes)
    {
        // Minimum lengths:
        // - Cookie token: 1 (version) + 16 (securityToken) + 1 (isCookieToken) = 18 bytes

View on GitHub (pinned to 3600ca084e)