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 bytesView on GitHub (pinned to 294cab2f9b)
Solutions
- 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(...).
- Ensure all application instances use the same key ring and application discriminator (SetApplicationName).
- 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.
- 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
- Persist data-protection keys to a durable store (Redis/SQL/Blob) in all environments.
- Share the same SetApplicationName across all instances that must validate each other's tokens.
- Don't share cookie names between apps with different data-protection purposes.
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
- The antiforgery cookie token and request token do not match.
- The required antiforgery cookie "{0}" is not present.
- The required antiforgery form field "{0}" is not present.
- The required antiforgery header value "{0}" is not present.
- The required antiforgery request token was not provided in e
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/3fe2a5e679a970a4.
Report an issue: GitHub.