Callout endpoint or Authorization header built in code
ID |
apex.maintainability.suggest_named_credentials |
Severity |
high |
Remediation Complexity |
medium |
Remediation Risk |
medium |
Remediation Effort |
medium |
Resource |
Api Usage |
Language |
Apex |
Description
Reports an HttpRequest whose endpoint is a literal URL rather than a callout: reference, or whose Authorization header is assembled in Apex.
Rationale
A Named Credential holds the endpoint and the authentication together, outside the code: the URL can be pointed at a sandbox of the remote system per org, the token is stored encrypted, and the platform refreshes an OAuth credential on its own. Built in Apex instead, both become deployment-time constants - the sandbox calls the production system because the URL is compiled in, and rotating a token means editing a class, running the tests and deploying. The secret also ends up wherever the class does: the metadata API, the repository, and anyone with read access to the class.
The following code illustrates the pattern detected by this rule:
public class BillingClient {
public HttpRequest legacyEndpoint() {
HttpRequest req = new HttpRequest();
// FLAGGED: Callout endpoint or Authorization header built in code
req.setEndpoint('https://billing.example.com/api/invoices');
return req;
}
public HttpRequest legacyAuth(String token) {
HttpRequest req = new HttpRequest();
// FLAGGED: Callout endpoint or Authorization header built in code
req.setHeader('Authorization', 'Bearer ' + token);
return req;
}
public HttpRequest namedCredential() {
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:Billing_API/invoices');
return req;
}
public HttpRequest contentType() {
HttpRequest req = new HttpRequest();
req.setHeader('Content-Type', 'application/json');
return req;
}
}
Remediation
Create a Named Credential and call req.setEndpoint('callout:My_Credential/path'); the platform then supplies the host and the Authorization header itself, and neither appears in the code. Where the remote system needs a header the credential cannot produce, keep the endpoint in the credential and read only that one value from Custom Metadata.