{"record":{"id":"3a6ebdf7440d4eaf","repo":"spring-projects/spring-security","slug":"targeturi-must-be-a-valid-url","errorCode":null,"errorMessage":"targetUri must be a valid URL","messagePattern":"targetUri must be a valid URL","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofContext.java","lineNumber":175,"sourceCode":"\t\t\tAssert.hasText(this.method, \"method cannot be empty\");\n\t\t\tAssert.hasText(this.targetUri, \"targetUri cannot be empty\");\n\t\t\tvalidate();\n\t\t\treturn new DPoPProofContext(this.dPoPProof, this.method, this.targetUri, this.accessToken);\n\t\t}\n\n\t\tprivate void validate() {\n\t\t\tif (!\"GET\".equals(this.method) && !\"HEAD\".equals(this.method) && !\"POST\".equals(this.method)\n\t\t\t\t\t&& !\"PUT\".equals(this.method) && !\"PATCH\".equals(this.method) && !\"DELETE\".equals(this.method)\n\t\t\t\t\t&& !\"OPTIONS\".equals(this.method) && !\"TRACE\".equals(this.method)) {\n\t\t\t\tthrow new IllegalArgumentException(\"method is invalid\");\n\t\t\t}\n\t\t\tURI uri;\n\t\t\ttry {\n\t\t\t\turi = new URI(this.targetUri);\n\t\t\t\turi.toURL();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"targetUri must be a valid URL\", ex);\n\t\t\t}\n\t\t\tif (uri.getQuery() != null || uri.getFragment() != null) {\n\t\t\t\tthrow new IllegalArgumentException(\"targetUri cannot contain query or fragment parts\");\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n","sourceCodeStart":157,"sourceCodeEnd":185,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofContext.java#L157-L185","documentation":"DPoPProofContext.validate parses the targetUri and requires it to be convertible to a java.net.URL. If new URI(...) fails or URI.toURL() fails (missing scheme, invalid characters, unknown protocol), an IllegalArgumentException with this message is thrown. DPoP proofs must bind to a well-formed absolute HTTP(S) URI.","triggerScenarios":"Constructing a DPoPProofContext with a targetUri that is relative (e.g. \"/path\"), lacks a scheme (\"example.com/path\"), uses an unknown scheme, or contains characters illegal in a URL.","commonSituations":"Passing only the path/endpoint portion instead of the full URL from configuration, environment-specific config with a typo, or user-supplied token-endpoint URLs that were not validated at startup.","solutions":["Pass an absolute URI including scheme, e.g. https://auth.example.com/oauth2/token.","Validate the URI at startup: new URI(uri).toURL() in a try-catch before use.","If you only have a path, prepend the configured issuer base URL.","Prefer building the URI with UriComponentsBuilder.fromHttpUrl(...) to fail early with a clearer message."],"exampleFix":"// before\nnew DPoPProofContext(\"POST\", \"/oauth2/token\", ...); // throws\n// after\nnew DPoPProofContext(\"POST\", \"https://server.example.com/oauth2/token\", ...);","handlingStrategy":"validation","validationCode":"URI uri = URI.create(targetUri);\nuri.toURL(); // throws MalformedURLException if not a valid absolute URL","typeGuard":"boolean isAbsoluteHttpUrl(String s) {\n    try {\n        URL u = new URI(s).toURL();\n        return \"http\".equals(u.getProtocol()) || \"https\".equals(u.getProtocol());\n    } catch (Exception e) { return false; }\n}","tryCatchPattern":null,"preventionTips":["Always store full absolute token/resource endpoint URLs in configuration.","Validate configured URIs at application startup, not at proof-creation time.","Build URIs with UriComponentsBuilder.fromHttpUrl to fail with clearer errors.","Avoid concatenating base URLs and paths without trailing-slash normalization."],"tags":["dpop","url","validation","oauth2","spring-security"],"backgroundTag":"invalid-url","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}