{"record":{"id":"0bf9ac63292cf5a9","repo":"elsa-workflows/elsa-core","slug":"the-external-authentication-shared-handle-hashing-key-must","errorCode":null,"errorMessage":"The External Authentication shared handle-hashing key must be valid base64 containing at least 32 bytes.","messagePattern":"The External Authentication shared handle-hashing key must be valid base64 containing at least 32 bytes\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.ExternalAuthentication/Services/HmacExternalAuthenticationHandleHasher.cs","lineNumber":62,"sourceCode":"            throw new InvalidOperationException(\"External Authentication handle-hashing settings are required.\");\n\n        if (string.IsNullOrWhiteSpace(options.SharedKeyBase64))\n            return RandomNumberGenerator.GetBytes(32);\n\n        try\n        {\n            var key = Convert.FromBase64String(options.SharedKeyBase64);\n            if (key.Length >= 32)\n                return key;\n\n            CryptographicOperations.ZeroMemory(key);\n        }\n        catch (FormatException)\n        {\n            // The options validator reports the actionable configuration error at startup.\n        }\n\n        throw new InvalidOperationException(\"The External Authentication shared handle-hashing key must be valid base64 containing at least 32 bytes.\");\n    }\n}\n","sourceCodeStart":44,"sourceCodeEnd":65,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.ExternalAuthentication/Services/HmacExternalAuthenticationHandleHasher.cs#L44-L65","documentation":"When HandleHashing.SharedKeyBase64 is set, GetKey decodes it and requires at least 32 bytes (256 bits) of key material for HMAC-SHA-256. If the value is not valid base64, or decodes to fewer than 32 bytes, the hasher throws this InvalidOperationException rather than hashing with a weak or malformed key. An empty/whitespace value is allowed and means 'use a process-local random key'.","triggerScenarios":"Setting ExternalAuthentication:HandleHashing:SharedKeyBase64 to a string that is not valid base64 (FormatException swallowed, then thrown), or to valid base64 that decodes to under 32 bytes (e.g. a 16-byte key). Thrown when the hasher is constructed (options evaluated in the constructor), typically at application startup.","commonSituations":"Typing a hex or plain-text secret into SharedKeyBase64 instead of base64; generating a key with a 128-bit tool (e.g. openssl rand -base64 16) instead of 32 bytes; copy/paste introducing whitespace, quotes, or line breaks; changing config between multi-node deployments without re-generating a proper shared key.","solutions":["Generate a correct key and reconfigure: openssl rand -base64 32 (or RandomNumberGenerator.GetBytes(32)), then set ExternalAuthentication:HandleHashing:SharedKeyBase64 to that value — it must decode to exactly 32+ bytes.","If you only run a single node or develop locally, remove the SharedKeyBase64 value entirely so the hasher falls back to a process-local random key.","Fix base64 formatting: strip quotes/newlines/whitespace and confirm the string round-trips (Convert.FromBase64String succeeds and yields >= 32 bytes).","Check the startup options validator output, which reports the actionable configuration error before the hasher throws."],"exampleFix":"// before (16-byte key, too short)\n\"HandleHashing\": { \"SharedKeyBase64\": \"c2hvcnRrZXkxMjM0NTY3OA==\" }\n\n// after (32-byte key)\n// generated via: openssl rand -base64 32\n\"HandleHashing\": { \"SharedKeyBase64\": \"qU9uHm3P8Zo7v2sL0kXwRbJcN1dEfGhIjKlMnOpQrStUvWxYz=\" }","handlingStrategy":"validation","validationCode":"// validate SharedKeyBase64 before configuring\nvar value = configuration[\"ExternalAuthentication:HandleHashing:SharedKeyBase64\"];\nif (!string.IsNullOrWhiteSpace(value))\n{\n    byte[] key;\n    try { key = Convert.FromBase64String(value); }\n    catch (FormatException) { throw new InvalidOperationException(\"SharedKeyBase64 is not valid base64.\"); }\n    if (key.Length < 32)\n        throw new InvalidOperationException($\"SharedKeyBase64 must decode to >= 32 bytes (got {key.Length}).\");\n}\n// generate: Convert.ToBase64String(RandomNumberGenerator.GetBytes(32))","typeGuard":"static bool IsValidSharedKey(string? sharedKeyBase64)\n{\n    if (string.IsNullOrWhiteSpace(sharedKeyBase64)) return true; // empty means process-local key\n    try { return Convert.FromBase64String(sharedKeyBase64).Length >= 32; }\n    catch (FormatException) { return false; }\n}","tryCatchPattern":"try\n{\n    var hasher = new HmacExternalAuthenticationHandleHasher(optionsAccessor);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"valid base64 containing at least 32 bytes\"))\n{\n    logger.LogError(ex, \"Invalid ExternalAuthentication:HandleHashing:SharedKeyBase64 — must be base64 of >= 32 bytes.\");\n    throw;\n}","preventionTips":["Generate keys only with openssl rand -base64 32 or RandomNumberGenerator.GetBytes(32) — never hand-type or reuse a 128-bit key.","Keep the value free of quotes, newlines, and trailing whitespace when injecting via environment variables or secrets managers.","Enable the options validator on startup so config errors surface with an actionable message before the hasher throws.","Use the same 32-byte key on every node of a multi-node deployment so hashed handles remain stable."],"tags":["configuration","csharp","base64","cryptography"],"backgroundTag":"invalid-config-value","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}