{"record":{"id":"3fe2a5e679a970a4","repo":"dotnet/aspnetcore","slug":"the-antiforgery-token-could-not-be-decrypted","errorCode":null,"errorMessage":"The antiforgery token could not be decrypted.","messagePattern":"The antiforgery token could not be decrypted\\.","errorType":"exception","errorClass":"AntiforgeryValidationException","httpStatus":null,"severity":"error","filePath":"src/Antiforgery/src/Internal/DefaultAntiforgeryTokenSerializer.cs","lineNumber":86,"sourceCode":"                    return token;\n                }\n            }\n        }\n        catch (Exception ex)\n        {\n            // swallow all exceptions - homogenize error if something went wrong\n            innerException = ex;\n        }\n        finally\n        {\n            if (tokenBytesRent is not null)\n            {\n                ArrayPool<byte>.Shared.Return(tokenBytesRent);\n            }\n        }\n\n        // if we reached this point, something went wrong deserializing\n        throw new AntiforgeryValidationException(Resources.AntiforgeryToken_DeserializationFailed, innerException);\n    }\n\n    /* The serialized format of the anti-XSRF token is as follows:\n     * Version: 1 byte integer\n     * SecurityToken: 16 byte binary blob\n     * IsCookieToken: 1 byte Boolean\n     * [if IsCookieToken != true]\n     *   +- IsClaimsBased: 1 byte Boolean\n     *   |  [if IsClaimsBased = true]\n     *   |    `- ClaimUid: 32 byte binary blob\n     *   |  [if IsClaimsBased = false]\n     *   |    `- Username: UTF-8 string with 7-bit integer length prefix\n     *   `- AdditionalData: UTF-8 string with 7-bit integer length prefix\n     */\n    private static AntiforgeryToken? Deserialize(ReadOnlySpan<byte> tokenBytes)\n    {\n        // Minimum lengths:\n        // - Cookie token: 1 (version) + 16 (securityToken) + 1 (isCookieToken) = 18 bytes","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/Antiforgery/src/Internal/DefaultAntiforgeryTokenSerializer.cs#L68-L104","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Persist and share DataProtection keys across all instances (configure AddDataProtection().PersistKeysToFileSystem/Redis with the same key ring and application discriminator).","Verify all nodes in the farm share the same antiforgery application name (AntiforgeryOptions or ApplicationDiscriminator).","Clear the stale antiforgery cookie on the client and obtain a fresh token from the server.","If crossing app versions/migrations, force a token refresh by rotating the data-protection keys."],"exampleFix":"// before: ephemeral keys per instance\nbuilder.Services.AddDataProtection();\n\n// after: shared persistent key ring across the farm\nbuilder.Services.AddDataProtection()\n    .PersistKeysToFileSystem(new DirectoryInfo(\"/shared/keys\"))\n    .SetApplicationName(\"MyApp\");","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await antiforgery.ValidateRequestAsync(httpContext); }\ncatch (AntiforgeryValidationException ex) when (ex.InnerException != null) { logger.LogWarning(\"Token decryption failed; possible key ring mismatch\"); return Results.BadRequest(); }","preventionTips":["Persist DataProtection keys to shared storage across all instances.","Set a stable ApplicationName/SetApplicationName so the key ring is consistent.","Log decryption failures distinctly to detect farm key drift quickly.","Rotate keys deliberately during migrations and document the rollout."],"tags":["antiforgery","aspnetcore","cryptography","data-protection","webfarm"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}