alibaba/nacos · error · IllegalStateException

Client secret is required for state signing

Error message

Client secret is required for state signing

What it means

Thrown by getSigningKey() when the configured client-secret is blank. The OIDC authorization-code flow reuses the client secret as the HMAC key to sign the self-contained state parameter (nonce.expirationTime.signature). Without it, CSRF state protection cannot operate.

Source

Thrown at plugin-default-impl/nacos-oidc-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/oidc/authenticate/AuthorizationCodeHandler.java:363

     * @param payload   the original payload
     * @param signature the signature to verify
     * @return true if signature is valid
     */
    private boolean hmacVerify(String payload, String signature) {
        String expectedSignature = hmacSign(payload);
        return expectedSignature.equals(signature);
    }
    
    /**
     * Get the signing key for HMAC operations.
     * Uses client secret as the signing key.
     *
     * @return signing key
     */
    private String getSigningKey() {
        String clientSecret = config.getClientSecret();
        if (StringUtils.isBlank(clientSecret)) {
            throw new IllegalStateException("Client secret is required for state signing");
        }
        return clientSecret;
    }
    
    /**
     * Build logout URL for RP-initiated logout.
     *
     * @param idToken     ID token for logout hint
     * @param redirectUri post-logout redirect URI
     * @return logout URL or null if not supported
     */
    public String buildLogoutUrl(String idToken, String redirectUri) {
        String endSessionEndpoint;
        try {
            endSessionEndpoint = metadataProvider.getMetadata().getEndSessionEndpoint();
        } catch (Exception e) {
            LOGGER.warn("Failed to discover OIDC logout endpoint: {}", e.getMessage());
            return null;

View on GitHub (pinned to 9b989acdf1)

Solutions

  1. Set nacos.plugin.auth.oidc.client-secret to a non-blank value matching the IdP client registration.
  2. If using a public/PKCE-only client with no secret, this built-in handler does not support it — register a confidential client with the IdP instead.
  3. Verify the config map actually delivers the secret (check OidcAuthPluginConfig.getClientSecret()).

Example fix

// before
nacos.plugin.auth.oidc.client-id=public-client
// no client-secret configured
// after: register a confidential client and supply its secret
nacos.plugin.auth.oidc.client-id=confidential-client
nacos.plugin.auth.oidc.client-secret=generated-secret
Defensive patterns

Strategy: validation

Validate before calling

// Validate at startup that the authorization-code flow can sign state
if (config.isJwtValidation() /* or auth-code flow enabled */
        && StringUtils.isBlank(config.getClientSecret())) {
    throw new IllegalStateException(
        "client-secret is required for OIDC authorization-code flow");
}

Prevention

When it happens

Trigger: buildAuthorizationUrl() or verifyAndDecodeState() runs while config.getClientSecret() returns blank — i.e. the authorization-code login flow is active but client-secret was never set.

Common situations: Public (PKCE-only) OIDC client that legitimately has no secret but the built-in handler requires one; client-secret key mistyped; secret intentionally left blank during testing; migrating from a flow that didn't need signing.

Related errors


AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14). Data as JSON: /api/errors/616243102038104c. Report an issue: GitHub.