justauth/JustAuth · error · AuthException

Invalid key

Error message

Invalid key: ${Arrays.toString(key)}

What it means

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.

Solutions

  1. 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.
  2. Check which credential maps to the signing key for that platform — some (e.g. agentId/clientSecret) are easily swapped.
  3. Load-test profiles: ensure the same config source is used in test and prod.
  4. If you control the code path, reject empty secrets at startup instead of letting sign() fail mid-request.

Example fix

// before
AuthConfig cfg = AuthConfig.builder().clientId(id).redirectUri(uri).build(); // secret forgotten
new AuthDingTalkRequest(cfg, cache).getAccessToken(callback);

// after
if (StringUtil.isEmpty(cfg.getClientSecret())) {
    throw new IllegalStateException("clientSecret required for this platform");
}
AuthConfig cfg = AuthConfig.builder().clientId(id).clientSecret(secret).redirectUri(uri).build();
Defensive patterns

Strategy: validation

Validate before calling

if (StringUtils.isEmpty(config.getClientSecret())) {
    throw new IllegalStateException("clientSecret is required for " + source.getName());
}

Try / catch

catch (AuthException e) { if (e.getMessage() != null && e.getMessage().startsWith("Invalid key:")) { /* credential missing/mismatched — never log the key bytes this message contains */ } }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of justauth/JustAuth@694bbf1b01 (2026-08-14). Data as JSON: /api/errors/f08784f3639b0d1c. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/me/zhyd/oauth/utils/GlobalAuthUtils.java:57

    }

    /**
     * 签名
     *
     * @param key       key
     * @param data      data
     * @param algorithm algorithm
     * @return byte[]
     */
    private static byte[] sign(byte[] key, byte[] data, String algorithm) {
        try {
            Mac mac = Mac.getInstance(algorithm);
            mac.init(new SecretKeySpec(key, algorithm));
            return mac.doFinal(data);
        } catch (NoSuchAlgorithmException ex) {
            throw new AuthException("Unsupported algorithm: " + algorithm, ex);
        } catch (InvalidKeyException ex) {
            throw new AuthException("Invalid key: " + Arrays.toString(key), ex);
        }
    }

    /**
     * 编码
     *
     * @param value str
     * @return encode str
     */
    public static String urlEncode(String value) {
        if (value == null) {
            return "";
        }
        try {
            String encoded = URLEncoder.encode(value, GlobalAuthUtils.DEFAULT_ENCODING.displayName());
            return encoded.replace("+", "%20").replace("*", "%2A").replace("~", "%7E").replace("/", "%2F");
        } catch (UnsupportedEncodingException e) {
            throw new AuthException("Failed To Encode Uri", e);

View on GitHub (pinned to 694bbf1b01)