{"record":{"id":"d9430cb0be20850e","repo":"jwtk/jjwt","slug":"unable-to-convert-base64-string-s-to-x509cert","errorCode":null,"errorMessage":"Unable to convert Base64 String '${s}' to X509Certificate instance. Cause: ${e.getMessage()}","messagePattern":"Unable to convert Base64 String '(.+?)' to X509Certificate instance\\. Cause: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/security/JwtX509StringConverter.java","lineNumber":71,"sourceCode":"        } finally {\n            Bytes.clear(der);\n        }\n    }\n\n    // visible for testing\n    protected X509Certificate toCert(final byte[] der) throws SecurityException {\n        return new JcaTemplate(\"X.509\").generateX509Certificate(der);\n    }\n\n    @Override\n    public X509Certificate applyFrom(CharSequence s) {\n        Assert.hasText(s, \"X.509 Certificate encoded string cannot be null or empty.\");\n        try {\n            byte[] der = Decoders.BASE64.decode(s); //RFC requires Base64, not Base64Url\n            return toCert(der);\n        } catch (Exception e) {\n            String msg = \"Unable to convert Base64 String '\" + s + \"' to X509Certificate instance. Cause: \" + e.getMessage();\n            throw new IllegalArgumentException(msg, e);\n        }\n    }\n}\n","sourceCodeStart":53,"sourceCodeEnd":75,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/security/JwtX509StringConverter.java#L53-L75","documentation":"JwtX509StringConverter.applyFrom decodes a Base64 string (the x5c header value) back into an X509Certificate. If Base64 decoding or certificate parsing fails for any reason, it throws IllegalArgumentException with this message wrapping the original cause. Note the input must be standard Base64, not Base64URL, per RFC 7515.","triggerScenarios":"Reading an x5c header value that is invalid Base64, Base64URL-encoded instead of Base64 (contains '-'/'_'), has whitespace/newlines, does not include the leading certificate bytes, or is otherwise not parseable as X.509 DER.","commonSituations":"Manually building an x5c header from a PEM file while forgetting to strip the BEGIN/END lines; using a Base64URL encoder by mistake; header values altered by URL-encoding or line-wrapping; certificates generated by tooling with wrong formats.","solutions":["Verify the string is standard Base64 (alphabet A-Za-z0-9+/ with = padding), not Base64URL.","Strip PEM headers/footers and whitespace before passing the value.","Decode and validate the string manually with java.util.Base64.getDecoder() and CertificateFactory to see the underlying cause.","Use JwtX509StringConverter (or jjwt) to produce the string in the first place instead of hand-rolling encoding."],"exampleFix":"// before\nString x5c = Base64.getUrlEncoder().encodeToString(cert.getEncoded()); // wrong alphabet\n\n// after\nString x5c = Base64.getEncoder().encodeToString(cert.getEncoded()); // standard Base64 per RFC","handlingStrategy":"validation","validationCode":"boolean isStandardBase64(String s) {\n    return s != null && s.matches(\"[A-Za-z0-9+/]+={0,2}\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    X509Certificate cert = converter.applyFrom(x5cValue);\n} catch (IllegalArgumentException e) {\n    logger.error(\"Bad x5c value '{}': {}\", x5cValue, e.getCause());\n    // fix encoding (URL-safe -> standard) or re-encode from the cert\n}","preventionTips":["Use java.util.Base64.getEncoder() (not getUrlEncoder) for x5c values.","Strip PEM BEGIN/END lines and whitespace before embedding certificates in x5c.","Round-trip test: applyTo then applyFrom should reproduce the certificate."],"tags":["x509","base64","certificate","jwt-header","jsonwebtoken"],"backgroundTag":"invalid-argument-format","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}