{"record":{"id":"5f080af12db23e2e","repo":"spring-projects/spring-security","slug":"unsupported-protectionpolicy-policy","errorCode":null,"errorMessage":"Unsupported ProtectionPolicy <policy>","messagePattern":"Unsupported ProtectionPolicy <policy>","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/CredProtectAuthenticationExtensionsClientInputJackson2Serializer.java","lineNumber":64,"sourceCode":"\t@Override\n\tpublic void serialize(CredProtectAuthenticationExtensionsClientInput input, JsonGenerator jgen,\n\t\t\tSerializerProvider provider) throws IOException {\n\t\tCredProtectAuthenticationExtensionsClientInput.CredProtect credProtect = input.getInput();\n\t\tString policy = toString(credProtect.getCredProtectionPolicy());\n\t\tjgen.writeObjectField(\"credentialProtectionPolicy\", policy);\n\t\tjgen.writeObjectField(\"enforceCredentialProtectionPolicy\", credProtect.isEnforceCredentialProtectionPolicy());\n\t}\n\n\tprivate static String toString(CredProtectAuthenticationExtensionsClientInput.CredProtect.ProtectionPolicy policy) {\n\t\tswitch (policy) {\n\t\t\tcase USER_VERIFICATION_OPTIONAL:\n\t\t\t\treturn \"userVerificationOptional\";\n\t\t\tcase USER_VERIFICATION_OPTIONAL_WITH_CREDENTIAL_ID_LIST:\n\t\t\t\treturn \"userVerificationOptionalWithCredentialIdList\";\n\t\t\tcase USER_VERIFICATION_REQUIRED:\n\t\t\t\treturn \"userVerificationRequired\";\n\t\t\tdefault:\n\t\t\t\tthrow new IllegalArgumentException(\"Unsupported ProtectionPolicy \" + policy);\n\t\t}\n\t}\n\n}\n","sourceCodeStart":46,"sourceCodeEnd":69,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/CredProtectAuthenticationExtensionsClientInputJackson2Serializer.java#L46-L69","documentation":"The Jackson2 serializer for CredProtectAuthenticationExtensionsClientInput maps each ProtectionPolicy enum constant to its WebAuthn wire-format string; if the switch sees a policy constant it does not recognize, it throws this IllegalArgumentException. This only occurs with an enum value added in a newer webauthn4j version than this serializer supports.","triggerScenarios":"Serializing a CredProtectExtensionOutput/CredProtectAuthenticationExtensionsClientInput whose ProtectionPolicy is USER_VERIFICATION_OPTIONAL_AND_CREDENTIAL_ID_LIST (or any constant not covered by the serializer's cases), typically after upgrading webauthn4j without updating the Jackson serializer's switch.","commonSituations":"Dependency version mismatch: spring-security-webauthn compiled against an older webauthn4j while a newer one (with a new enum constant) is on the classpath; manually constructing a ProtectionPolicy from client extension output carrying an unexpected policy.","solutions":["Align webauthn4j and spring-security-webauthn versions (upgrade spring-security so its serializer knows the new enum constant, or downgrade webauthn4j to the supported version).","Log the policy value to identify which constant is missing and add a case for it in the switch.","If client-supplied, reject or coerce unknown policy values before building the extension input object."],"exampleFix":"// before (dependency)\n<dependency><groupId>com.webauthn4j</groupId><artifactId>webauthn4j-core</artifactId><version>0.29.0.RELEASE</version></dependency>\n// after — match the version spring-security-webauthn was built against\n<dependency><groupId>com.webauthn4j</groupId><artifactId>webauthn4j-core</artifactId><version>0.28.5.RELEASE</version></dependency>","handlingStrategy":"validation","validationCode":"ProtectionPolicy policy = input.getProtectionPolicy();\nif (!(policy == ProtectionPolicy.USER_VERIFICATION_OPTIONAL\n   || policy == ProtectionPolicy.USER_VERIFICATION_OPTIONAL_WITH_CREDENTIAL_ID_LIST\n   || policy == ProtectionPolicy.USER_VERIFICATION_REQUIRED)) {\n    throw new IllegalArgumentException(\"Unsupported policy before serialization: \" + policy);\n}\n","typeGuard":"public static boolean isSerializablePolicy(ProtectionPolicy p) {\n    return switch (p) {\n        case USER_VERIFICATION_OPTIONAL,\n             USER_VERIFICATION_OPTIONAL_WITH_CREDENTIAL_ID_LIST,\n             USER_VERIFICATION_REQUIRED -> true;\n        default -> false;\n    };\n}\n","tryCatchPattern":"try {\n    objectMapper.writeValueAsString(extensionInput);\n} catch (IllegalArgumentException e) {\n    if (!e.getMessage().startsWith(\"Unsupported ProtectionPolicy\")) throw e;\n    log.error(\"Unknown credProtect policy {} — check webauthn4j version alignment\", e.getMessage());\n    throw e;\n}\n","preventionTips":["Keep webauthn4j and spring-security-webauthn versions aligned in your dependency management","Run serialization of extension inputs in integration tests after any dependency upgrade","Check the classpath for duplicate/mixed webauthn4j jars (mvn dependency:tree)","Add exhaustive switch checks on enums in custom serializers so new constants fail at compile time"],"tags":["webauthn","jackson","serialization","enum"],"backgroundTag":"unsupported-enum-value","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}