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 DefaultAntiforgeryTokenSerializer.Deserialize (line 86) when the serialized token cannot be decrypted or parsed. The method catches all exceptions during base64-decoding, data-protection Unprotect, and binary deserialization, then throws a homogenized AntiforgeryValidationException with the original error as innerException. Common underlying causes include data-protection key loss, corrupted tokens, or format-version mismatches.

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 294cab2f9b)

Solutions

  1. Persist data protection keys to a durable store (Redis, SQL Server, Azure Blob, filesystem) so they survive restarts and are shared across instances: builder.Services.AddDataProtection().PersistKeysToRedis(...).
  2. Ensure all application instances use the same key ring and application discriminator (SetApplicationName).
  3. If keys were genuinely lost, clear the old antiforgery cookie in the browser and call GetAndStoreTokens to mint fresh tokens under the new key ring.
  4. Check that the token isn't being URL-encoded/decoded inconsistently between generation and consumption.

Example fix

// before — ephemeral in-memory keys (lost on restart)
builder.Services.AddDataProtection();

// after — persist keys to Redis for multi-instance durability
var redis = ConnectionMultiplexer.Connect(redisConnStr);
builder.Services.AddDataProtection()
    .PersistKeysToStackExchangeRedis(redis, "DataProtection-Keys")
    .SetApplicationName("my-app");
Defensive patterns

Strategy: try-catch

Try / catch

try
{
    await _antiforgery.ValidateRequestAsync(HttpContext);
}
catch (AntiforgeryValidationException ex) when (ex.Message.Contains("could not be decrypted"))
{
    // Clear the stale cookie and redirect to get fresh tokens
    Response.Cookies.Delete(".AspNetCore.Antiforgery");
    return Redirect(Request.Path);
}

Prevention

When it happens

Trigger: Deserialize is called with a token string that fails any step in: WebEncoders.Base64UrlDecode, _defaultCryptoSystem.Unprotect (data protection), or the private Deserialize(ReadOnlySpan<byte>) format parser (which returns null for wrong version/length/trailing bytes).

Common situations: Data protection keys were not persisted and the app restarted (in-memory keys lost); the app moved to a different machine/container without persisting the key ring; multiple apps sharing the same cookie name but different data-protection purposes; the token string was truncated or URL-mangled; a version upgrade changed the token format (TokenVersion mismatch).

Related errors


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