{"record":{"id":"f5cab6c4946cd1e4","repo":"abpframework/abp","slug":"the-dapr-app-api-token-provided-in-the-dapr-api","errorCode":null,"errorMessage":"The Dapr App API Token (provided in the 'dapr-api-token' HTTP header) doesn't match the expected value!","messagePattern":"The Dapr App API Token \\(provided in the 'dapr-api-token' HTTP header\\) doesn't match the expected value!","errorType":"http","errorClass":"AbpAuthorizationException","httpStatus":403,"severity":"error","filePath":"framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/DaprAppApiTokenValidator.cs","lineNumber":36,"sourceCode":"    }\n\n    public virtual void CheckDaprAppApiToken()\n    {\n        var expectedAppApiToken = GetConfiguredAppApiTokenOrNull();\n        if (expectedAppApiToken.IsNullOrWhiteSpace())\n        {\n            return;\n        }\n\n        var headerAppApiToken = GetDaprAppApiTokenOrNull();\n        if (headerAppApiToken.IsNullOrWhiteSpace())\n        {\n            throw new AbpAuthorizationException(\"Expected Dapr App API Token is not provided! Dapr should set the 'dapr-api-token' HTTP header.\");\n        }\n\n        if (expectedAppApiToken != headerAppApiToken)\n        {\n            throw new AbpAuthorizationException(\"The Dapr App API Token (provided in the 'dapr-api-token' HTTP header) doesn't match the expected value!\");\n        }\n    }\n\n    public virtual bool IsValidDaprAppApiToken()\n    {\n        var expectedAppApiToken = GetConfiguredAppApiTokenOrNull();\n        if (expectedAppApiToken.IsNullOrWhiteSpace())\n        {\n            return true;\n        }\n\n        var headerAppApiToken = GetDaprAppApiTokenOrNull();\n        return expectedAppApiToken == headerAppApiToken;\n    }\n\n    public virtual string? GetDaprAppApiTokenOrNull()\n    {\n        string? apiTokenHeader = HttpContext.Request.Headers[\"dapr-api-token\"];","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/abpframework/abp/blob/7ed43b1931b9df46a50c0c59148a18645641d0df/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/DaprAppApiTokenValidator.cs#L18-L54","documentation":"Thrown by DaprAppApiTokenValidator.CheckDaprAppApiToken when both an expected token is configured AND a 'dapr-api-token' header is present, but the two values differ. This is a constant-time-ish equality miss: the request looks like a Dapr call but the secret does not match, so ABP rejects it as an authorization failure.","triggerScenarios":"CheckDaprAppApiToken() runs on a request that carries a 'dapr-api-token' header whose value != the configured AppApiToken.","commonSituations":"Token rotated on one side only (host or Dapr); copy/paste typo or trailing whitespace/newline in either the config or the secret; multiple environments (dev token sent to prod host); secret store returned a stale value after redeploy.","solutions":["Verify the configured AppApiToken in the host exactly equals the 'app-api-token' secret supplied to Dapr (trim whitespace, compare byte-for-byte).","Re-issue the token from a single source and redeploy both the host and the Dapr secret together.","Check for trailing newlines in the secret (common when reading from a file/k8s secret).","Temporarily log the expected-vs-header length (not the value) to confirm a mismatch cause."],"exampleFix":"// before: tokens differ -> AbpAuthorizationException: ... doesn't match\n\n// after: derive both from one secret\n# host: \"Dapr\": { \"AppApiToken\": \"${DAPR_APP_API_TOKEN}\" }\n# dapr: dapr run --app-api-token \"$DAPR_APP_API_TOKEN\" ...","handlingStrategy":"try-catch","validationCode":"var expected = daprApiTokenProvider.GetAppApiToken();\nvar header = httpContext.Request.Headers[\"dapr-api-token\"].ToString();\nif (!string.IsNullOrEmpty(expected) && expected != header)\n{\n    // mismatch - log lengths (not values), trigger re-sync\n}","typeGuard":"null","tryCatchPattern":"try { daprAppApiTokenValidator.CheckDaprAppApiToken(); }\ncatch (AbpAuthorizationException ex) when (ex.Message.Contains(\"doesn't match\"))\n{ /* return 401; trigger token re-sync between host and sidecar */ }","preventionTips":["Source the token for host and Dapr from the same secret.","Trim whitespace/newlines when reading the secret from files or k8s secrets.","Rotate tokens atomically (both sides redeployed together).","Compare lengths first when debugging mismatches (never log the value)."],"tags":["dapr","authentication","security","configuration","token-mismatch"],"backgroundTag":null,"analyzedSha":"7ed43b1931b9df46a50c0c59148a18645641d0df","analyzedAt":"2026-08-13T16:26:11.351Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}