{"record":{"id":"e9911393a9149d7d","repo":"alibaba/nacos","slug":"token-secret-key-change-requires-restart","errorCode":null,"errorMessage":"Token secret key change requires restart","messagePattern":"Token secret key change requires restart","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"plugin-default-impl/nacos-default-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/token/TokenManagerDelegate.java","lineNumber":65,"sourceCode":"    }\n    \n    private TokenManager getExecuteTokenManager() {\n        JwtTokenManager direct = tokenManager;\n        CachedJwtTokenManager cached = cachedTokenManager;\n        if (direct == null || cached == null) {\n            throw new IllegalStateException(\"Nacos auth plugin has not been initialized\");\n        }\n        return configProvider.getConfig().isTokenCacheEnabled() ? cached : direct;\n    }\n    \n    /**\n     * Initialize token managers once and clear cached state after relevant config changes.\n     */\n    public synchronized void applyTokenConfig() {\n        NacosAuthPluginConfig current = configProvider.getConfig();\n        if (lastAppliedConfig != null && !Objects.equals(lastAppliedConfig.getTokenSecretKey(),\n            current.getTokenSecretKey())) {\n            throw new IllegalArgumentException(\"Token secret key change requires restart\");\n        }\n        if (tokenManager == null) {\n            JwtTokenManager direct = new JwtTokenManager(configProvider);\n            CachedJwtTokenManager cached = new CachedJwtTokenManager(direct, configProvider);\n            tokenManager = direct;\n            cachedTokenManager = cached;\n        } else if (shouldClearCache(current)) {\n            cachedTokenManager.clear();\n        }\n        lastAppliedConfig = current;\n    }\n    \n    private boolean shouldClearCache(NacosAuthPluginConfig current) {\n        return lastAppliedConfig.getTokenExpireSeconds() != current.getTokenExpireSeconds()\n            || lastAppliedConfig.isTokenCacheEnabled() != current.isTokenCacheEnabled();\n    }\n    \n    /**","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/plugin-default-impl/nacos-default-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/token/TokenManagerDelegate.java#L47-L83","documentation":"The token secret key is the HMAC key for every issued JWT; changing it at runtime would invalidate all outstanding tokens instantly and is therefore refused. applyTokenConfig() compares the currently-applied key against the freshly-read one and throws IllegalArgumentException if they differ and a key was already applied. The only supported way to rotate the key is a full server restart so all in-memory token state is rebuilt consistently.","triggerScenarios":"Editing nacos.plugin.auth.nacos.token.secret.key in application.properties (or via a config-change event) while the server is running, then triggering a refresh that calls applyTokenConfig() a second time with the new key.","commonSituations":"Operator rotates the secret key via hot reload expecting tokens to keep working; an external config manager pushes a new key to a live node; clustered nodes given divergent keys one at a time.","solutions":["Do not hot-swap the secret key. To rotate: set the new key in config, then restart every Nacos node in a coordinated maintenance window.","If hit during a failed hot reload, revert the key to the previous value and restart the node.","Distribute the same key to all cluster members before restarting to avoid cross-node token mismatch.","After rotation, force clients to re-login (old tokens are invalid)."],"exampleFix":"// before (hot reload triggers the error)\n// config change event -> applyTokenConfig() -> IllegalArgumentException\n\n// after: rotate only via restart\n// 1. set nacos.plugin.auth.nacos.token.secret.key=<newKey> in application.properties\n// 2. stop all nodes\n// 3. start all nodes (applyTokenConfig runs once with the new key, lastAppliedConfig==null)","handlingStrategy":"validation","validationCode":"// Reject secret-key changes at config-load time instead of letting applyTokenConfig throw.\nString newKey = configProvider.getConfig().getTokenSecretKey();\nString appliedKey = lastAppliedConfig == null ? null : lastAppliedConfig.getTokenSecretKey();\nif (appliedKey != null && !Objects.equals(appliedKey, newKey)) {\n    log.error(\"token secret key changed at runtime; restart required. Refusing hot reload.\");\n    // do NOT call applyTokenConfig() with the new key\n}","typeGuard":null,"tryCatchPattern":"try {\n    delegate.applyTokenConfig();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"secret key change\")) {\n        log.error(\"secret key rotation requires restart; reverting\");\n        // revert config to previous key and schedule restart\n    }\n    throw e;\n}","preventionTips":["Never hot-swap nacos.plugin.auth.nacos.token.secret.key; rotate via a coordinated restart.","Distribute the same key to all cluster members before restarting.","Lock down who can edit the secret key in config management.","After rotation, force clients to re-login."],"tags":["auth","token","jwt","configuration","secret-key"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}