{"record":{"id":"4c846ec295386d43","repo":"signalapp/Signal-Server","slug":"bad-decoded-value","errorCode":null,"errorMessage":"Bad decoded value: ","messagePattern":"Bad decoded value: ","errorType":"http","errorClass":"InvalidAuthorizationHeaderException","httpStatus":401,"severity":"error","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/auth/BasicAuthorizationHeader.java","lineNumber":50,"sourceCode":"        throw new InvalidAuthorizationHeaderException(\"Invalid authorization header: \" + header);\n      }\n\n      final String authorizationType = header.substring(0, spaceIndex);\n\n      if (!\"Basic\".equals(authorizationType)) {\n        throw new InvalidAuthorizationHeaderException(\"Unsupported authorization method: \" + authorizationType);\n      }\n\n      final String credentials;\n\n      try {\n        credentials = new String(Base64.getDecoder().decode(header.substring(spaceIndex + 1)));\n      } catch (final IndexOutOfBoundsException e) {\n        throw new InvalidAuthorizationHeaderException(\"Missing credentials\");\n      }\n\n      if (StringUtils.isEmpty(credentials)) {\n        throw new InvalidAuthorizationHeaderException(\"Bad decoded value: \" + credentials);\n      }\n\n      final int credentialSeparatorIndex = credentials.indexOf(':');\n\n      if (credentialSeparatorIndex == -1) {\n        throw new InvalidAuthorizationHeaderException(\"Badly-formatted credentials: \" + credentials);\n      }\n\n      final String usernameComponent = credentials.substring(0, credentialSeparatorIndex);\n\n      final String username;\n      final byte deviceId;\n      {\n        final Pair<String, Byte> identifierAndDeviceId =\n            AccountAuthenticator.getIdentifierAndDeviceId(usernameComponent);\n\n        username = identifierAndDeviceId.first();\n        deviceId = identifierAndDeviceId.second();","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/auth/BasicAuthorizationHeader.java#L32-L68","documentation":"After decoding, fromString throws InvalidAuthorizationHeaderException(\"Bad decoded value: <credentials>\") when the decoded credential string is empty (StringUtils.isEmpty). The Base64 payload was valid but encoded an empty string.","triggerScenarios":"Sending 'Basic ' + base64(\"\") — e.g. an empty username:password; a client encoding nothing after building the credentials string incorrectly.","commonSituations":"Empty config values for username/password; client code that does base64(user + \":\" + pass) where both are null/empty after String.valueOf(null) mishandling.","solutions":["Encode a non-empty 'username:password' string","Validate username/password are present in client config before encoding","Send the server-issued account identifier (e.g. E.164 number) and auth password"],"exampleFix":"// before\nString creds = base64(user + \":\" + pass); // both empty\n// after\nif (user.isEmpty() || pass.isEmpty()) throw new IllegalStateException(\"missing creds\");\nString creds = base64(user + \":\" + pass);","handlingStrategy":"validation","validationCode":"String decoded = new String(Base64.getDecoder().decode(credentialPart), StandardCharsets.UTF_8);\nif (decoded.isEmpty()) throw new IllegalArgumentException(\"empty basic credentials\");","typeGuard":null,"tryCatchPattern":"try { BasicAuthorizationHeader.fromString(header); } catch (InvalidAuthorizationHeaderException e) { throw new NotAuthorizedException(\"Basic\"); }","preventionTips":["Validate username/password are non-empty before encoding","Fail fast at client startup if auth config is empty"],"tags":["basic-auth","empty-value","credentials"],"backgroundTag":"empty-required-field","analyzedSha":"100ab61c82627582c867d19e1c0561ba2781e927","analyzedAt":"2026-09-09T13:29:47.883Z","contentChangedAt":"2026-09-09T13:29:47.883Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}