{"record":{"id":"f08784f3639b0d1c","repo":"justauth/JustAuth","slug":"invalid-key-arrays-tostring-key","errorCode":null,"errorMessage":"Invalid key: ${Arrays.toString(key)}","messagePattern":"Invalid key: (.+?)","errorType":"exception","errorClass":"AuthException","httpStatus":null,"severity":"error","filePath":"src/main/java/me/zhyd/oauth/utils/GlobalAuthUtils.java","lineNumber":57,"sourceCode":"    }\n\n    /**\n     * 签名\n     *\n     * @param key       key\n     * @param data      data\n     * @param algorithm algorithm\n     * @return byte[]\n     */\n    private static byte[] sign(byte[] key, byte[] data, String algorithm) {\n        try {\n            Mac mac = Mac.getInstance(algorithm);\n            mac.init(new SecretKeySpec(key, algorithm));\n            return mac.doFinal(data);\n        } catch (NoSuchAlgorithmException ex) {\n            throw new AuthException(\"Unsupported algorithm: \" + algorithm, ex);\n        } catch (InvalidKeyException ex) {\n            throw new AuthException(\"Invalid key: \" + Arrays.toString(key), ex);\n        }\n    }\n\n    /**\n     * 编码\n     *\n     * @param value str\n     * @return encode str\n     */\n    public static String urlEncode(String value) {\n        if (value == null) {\n            return \"\";\n        }\n        try {\n            String encoded = URLEncoder.encode(value, GlobalAuthUtils.DEFAULT_ENCODING.displayName());\n            return encoded.replace(\"+\", \"%20\").replace(\"*\", \"%2A\").replace(\"~\", \"%7E\").replace(\"/\", \"%2F\");\n        } catch (UnsupportedEncodingException e) {\n            throw new AuthException(\"Failed To Encode Uri\", e);","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/justauth/JustAuth/blob/694bbf1b010d93404e3bfb4824d90e9ddfaebebb/src/main/java/me/zhyd/oauth/utils/GlobalAuthUtils.java#L39-L75","documentation":"Internal guard in GlobalAuthUtils.sign: SecretKeySpec/Mac.init threw InvalidKeyException, i.e. the key bytes are unusable for the requested MAC. In practice this means the key material was null-derived or degenerate — typically an empty client-secret/agent credential reaching the signature path. The message leaks the raw key bytes via Arrays.toString(key), which itself is worth noting for log hygiene with real secrets.","triggerScenarios":"A JustAuth request class calls GlobalAuthUtils.sign (or exchangeCgtx/dingtalk-style signing) with a byte[] key built from a secret that is null or zero-length, e.g. config.getClientSecret() missing while a signature-secured endpoint is invoked. Note: a null SecretKeySpec constructor usually fails earlier with IllegalArgumentException, so the realistic path is a provider/key mismatch or empty-key edge on certain JVMs.","commonSituations":"AuthConfig built from env vars where the secret variable was unset; YAML indentation hiding the secret key; credentials swapped (clientId used as secret); provider config objects partially populated in tests/mocks.","solutions":["Verify the secret is non-empty before calling the SDK flow that signs requests (Douyin/DingTalk style agents): log config.getClientSecret() != null && !isBlank, never the value itself.","Check which credential maps to the signing key for that platform — some (e.g. agentId/clientSecret) are easily swapped.","Load-test profiles: ensure the same config source is used in test and prod.","If you control the code path, reject empty secrets at startup instead of letting sign() fail mid-request."],"exampleFix":"// before\nAuthConfig cfg = AuthConfig.builder().clientId(id).redirectUri(uri).build(); // secret forgotten\nnew AuthDingTalkRequest(cfg, cache).getAccessToken(callback);\n\n// after\nif (StringUtil.isEmpty(cfg.getClientSecret())) {\n    throw new IllegalStateException(\"clientSecret required for this platform\");\n}\nAuthConfig cfg = AuthConfig.builder().clientId(id).clientSecret(secret).redirectUri(uri).build();","handlingStrategy":"validation","validationCode":"if (StringUtils.isEmpty(config.getClientSecret())) {\n    throw new IllegalStateException(\"clientSecret is required for \" + source.getName());\n}","typeGuard":null,"tryCatchPattern":"catch (AuthException e) { if (e.getMessage() != null && e.getMessage().startsWith(\"Invalid key:\")) { /* credential missing/mismatched — never log the key bytes this message contains */ } }","preventionTips":["Assert all required credentials non-empty at startup per platform.","Use secret managers or env binding instead of hand-edited YAML to avoid silent blanks.","Never log this exception's message verbatim in production — it embeds the raw key bytes."],"tags":["java","justauth","crypto","credentials","configuration"],"backgroundTag":null,"analyzedSha":"694bbf1b010d93404e3bfb4824d90e9ddfaebebb","analyzedAt":"2026-08-14T15:16:59.945Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}