{"record":{"id":"a8b17db0d4578a61","repo":"dromara/Sa-Token","slug":"code-30302","errorCode":"CODE_30302","errorMessage":"jwt cannot delete token","messagePattern":"jwt cannot delete token","errorType":"exception","errorClass":"ApiDisabledException","httpStatus":null,"severity":"warning","filePath":"sa-token-plugin/sa-token-temp-jwt/src/main/java/cn/dev33/satoken/temp/jwt/SaTempTemplateForJwt.java","lineNumber":64,"sourceCode":"\t@Override\n\tpublic Object parseToken(String token) {\n\t\treturn SaJwtUtil.getValue(token, getJwtSecretKey());\n\t}\n\t\n\t/**\n\t * 返回指定token的剩余有效期，单位：秒 \n\t */\n\t@Override\n\tpublic long getTimeout(String token) {\n\t\treturn SaJwtUtil.getTimeout(token, getJwtSecretKey());\n\t}\n\n\t/**\n\t * 删除一个token\n\t */\n\t@Override\n\tpublic void deleteToken(String token) {\n\t\tthrow new ApiDisabledException(\"jwt cannot delete token\").setCode(SaTempJwtErrorCode.CODE_30302);\n\t}\n\n\t/**\n\t * 获取指定 value 的 temp-token 列表记录\n\t * @param value /\n\t * @return /\n\t */\n\tpublic List<String> getTempTokenList(Object value) {\n\t\tthrow new ApiDisabledException(\"jwt cannot get token list\").setCode(SaTempJwtErrorCode.CODE_30304);\n\t}\n\n\t/**\n\t * 获取jwt秘钥 \n\t * @return jwt秘钥 \n\t */\n\t@Override\n\tpublic String getJwtSecretKey() {\n\t\tString jwtSecretKey = SaManager.getConfig().getJwtSecretKey();","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/dromara/Sa-Token/blob/ac2c7f6e94a78573cf0bcb932dd8b04e68fad189/sa-token-plugin/sa-token-temp-jwt/src/main/java/cn/dev33/satoken/temp/jwt/SaTempTemplateForJwt.java#L46-L82","documentation":"ApiDisabledException from SaTempTemplateForJwt.deleteToken: the JWT-backed temp-token implementation is stateless, so tokens cannot be revoked or deleted — there is no storage backing them. Calling the inherited delete API is a category error for this implementation.","triggerScenarios":"Code written against the Redis/storage-backed SaTempTemplate calls deleteToken(token) while the jwt-temp plugin implementation is active.","commonSituations":"Swapping the temp-token implementation from storage-based to JWT without auditing call sites; generic cleanup/logout code paths that try to invalidate temp tokens.","solutions":["Remove the deleteToken call — rely on short token timeouts instead of revocation","If revocation is a hard requirement, switch to the storage-backed temp token (SaTempDefaultImpl) rather than JWT","Guard shared code paths with an instanceof check before calling delete APIs"],"exampleFix":"// before\nsaTempTemplate.deleteToken(token); // ApiDisabledException under jwt impl\n\n// after\nif(saTempTemplate instanceof SaTempTemplateForJwt) {\n    // stateless: nothing to delete, just wait for expiry\n} else {\n    saTempTemplate.deleteToken(token);\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"boolean isStatelessJwtTemp = SaManager.getSaTempTemplate() instanceof SaTempTemplateForJwt;","tryCatchPattern":"try { temp.deleteToken(t); } catch (ApiDisabledException e) { /* expected under jwt impl: no-op */ }","preventionTips":["Audit revocation call sites before switching temp-token implementations","Prefer short expirations over delete calls in stateless designs"],"tags":["sa-token","jwt","api-disabled","stateless"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}