{"record":{"id":"42972ed05247e1cd","repo":"spring-projects/spring-security","slug":"invalid-client-42972e","errorCode":"invalid_client","errorMessage":"Client authentication failed: x509_certificate_issuer","messagePattern":"Client authentication failed: x509_certificate_issuer","errorType":"error_code","errorClass":"OAuth2AuthenticationException","httpStatus":null,"severity":"error","filePath":"oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/X509SelfSignedCertificateVerifier.java","lineNumber":85,"sourceCode":"\tprivate static final String ERROR_URI = \"https://datatracker.ietf.org/doc/html/rfc6749#section-3.2.1\";\n\n\tprivate static final JWKMatcher HAS_X509_CERT_CHAIN_MATCHER = new JWKMatcher.Builder().hasX509CertChain(true)\n\t\t.build();\n\n\tprivate final Function<RegisteredClient, JWKSet> jwkSetSupplier = new JwkSetSupplier();\n\n\t@Override\n\tpublic void accept(OAuth2ClientAuthenticationContext clientAuthenticationContext) {\n\t\tOAuth2ClientAuthenticationToken clientAuthentication = clientAuthenticationContext.getAuthentication();\n\t\tRegisteredClient registeredClient = clientAuthenticationContext.getRegisteredClient();\n\t\tX509Certificate[] clientCertificateChain = (X509Certificate[]) clientAuthentication.getCredentials();\n\t\tAssert.notEmpty(clientCertificateChain, \"clientCertificateChain cannot be empty\");\n\t\tX509Certificate clientCertificate = clientCertificateChain[0];\n\n\t\tX500Principal issuer = clientCertificate.getIssuerX500Principal();\n\t\tX500Principal subject = clientCertificate.getSubjectX500Principal();\n\t\tif (issuer == null || !issuer.equals(subject)) {\n\t\t\tthrow invalidClient(\"x509_certificate_issuer\");\n\t\t}\n\n\t\tJWKSet jwkSet = this.jwkSetSupplier.apply(registeredClient);\n\n\t\tboolean publicKeyMatches = false;\n\t\tfor (JWK jwk : jwkSet.filter(HAS_X509_CERT_CHAIN_MATCHER).getKeys()) {\n\t\t\tX509Certificate x509Certificate = jwk.getParsedX509CertChain().get(0);\n\t\t\tPublicKey publicKey = x509Certificate.getPublicKey();\n\t\t\tif (Arrays.equals(clientCertificate.getPublicKey().getEncoded(), publicKey.getEncoded())) {\n\t\t\t\tpublicKeyMatches = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!publicKeyMatches) {\n\t\t\tthrow invalidClient(\"x509_certificate\");\n\t\t}\n\t}","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/X509SelfSignedCertificateVerifier.java#L67-L103","documentation":"This error is thrown during X.509 self-signed certificate client authentication when the presented certificate's issuer DN does not equal its subject DN. A self-signed certificate must have identical issuer and subject principals; anything else is not self-signed and cannot be used with this authenticator. The server rejects the client with an invalid_client OAuth2 error naming the failing parameter 'x509_certificate_issuer'.","triggerScenarios":"Calling OAuth2 client authentication with an X.509 certificate chain whose first certificate has issuer != subject, e.g. a CA-signed (end-entity) certificate submitted to X509SelfSignedCertificateVerifier.","commonSituations":"Developers configure a certificate issued by an internal CA (or a chained PKCS#12 entry) but register the client with a self-signed-certificate client authentication method; also happens when the wrong entry from a keystore is presented instead of the self-signed one.","solutions":["Generate a truly self-signed certificate (keytool -genkeypair -keyalg RSA without -issuer, or openssl req -x509) and register it in the client's JWK Set via the jwk_set_url client setting","Verify the certificate with: cert.getIssuerX500Principal().equals(cert.getSubjectX500Principal()) before configuring it","If you need CA-issued certificates, use a client authentication method that supports them instead of the self-signed verifier"],"exampleFix":"// before\ncertificate issued by Corporate CA -> presented as self-signed\n// after\nkeytool -genkeypair -alias client -keyalg RSA -keystore client.p12 -dname \"CN=client\"  # self-signed by construction","handlingStrategy":"validation","validationCode":"if (cert.getIssuerX500Principal() == null || !cert.getIssuerX500Principal().equals(cert.getSubjectX500Principal())) {\n    throw new IllegalArgumentException(\"certificate is not self-signed: issuer != subject\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    authenticator.accept(context);\n} catch (OAuth2AuthenticationException ex) {\n    // check ex.getError().getErrorCode() == \"invalid_client\" and description for x509_certificate_issuer\n}","preventionTips":["Use keytool -genkeypair or openssl req -x509 so issuer==subject by construction","Never submit CA-issued certificates to a self-signed certificate verifier","Log certificate issuer/subject DN at startup to confirm the right keystore entry is used"],"tags":["oauth2","x509","client-authentication","certificate"],"backgroundTag":"invalid-client-credentials","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}