apereo/cas · error
invalid_request
invalid_request
Error message
CAS cannot accept the request given the issuer is invalid.
What it means
OidcVerifiableCredentialTypeMetadataController.handle describes a credential configuration (by configurationId) for verifiable credentials. Before describing, it validates the request issuer against VC_CREDENTIAL_TYPE_URL; on failure it returns HTTP 400 'invalid_request' / 'Invalid issuer'.
Solutions
- Use the externally configured issuer host/path when requesting type metadata.
- Correct ingress/proxy Host and X-Forwarded-Proto headers.
- Ensure the configured issuer matches the URL scheme (https) and hostname presented by clients.
Example fix
// before curl https://10.0.0.5/cas/oidc/vc/credential-types/UniversityDegree_JWT // after curl https://sso.example.org/cas/oidc/vc/credential-types/UniversityDegree_JWT
Defensive patterns
Strategy: validation
Validate before calling
// Derive type metadata URL from issuer, not from cached/internal hosts
String typeUrl = issuer + "/vc/credential-types/" + configurationId;
if (!typeUrl.startsWith(issuer)) throw new IllegalArgumentException("URL not under issuer"); Try / catch
if (resp.status() == 400 && body.contains("Invalid issuer")) {
throw new IllegalStateException("Re-fetch issuer metadata and use its URLs");
} Prevention
- Refresh cached discovery documents after environment changes
- Avoid IP-address or internal-name access to OIDC endpoints
- Align issuer configuration with ingress host rules
When it happens
Trigger: GET the credential type metadata endpoint with a valid path configurationId but from a request whose issuer/host does not match the configured OIDC issuer.
Common situations: Clients caching discovery metadata from one environment and reusing host URLs from another; DNS aliases (internal vs external names); missing Host header preservation behind ingress.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- invalid_request
- invalid_request
- invalid_request
- Missing required principal attribute for claim
- Proof nonce is invalid or missing
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/a8831b5b432a2eff.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-oidc-vc/src/main/java/org/apereo/cas/oidc/vc/issuer/web/OidcVerifiableCredentialTypeMetadataController.java:60
/**
* Handle response entity.
*
* @param request the request
* @param response the response
* @return the response entity
*/
@GetMapping(value = {
'/' + OidcConstants.BASE_OIDC_URL + '/' + OidcConstants.VC_CREDENTIAL_TYPE_URL + "/{configurationId}",
"/**/" + OidcConstants.VC_CREDENTIAL_TYPE_URL + "/{configurationId}"},
produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Handle OIDC credential configuration type request",
description = "Handles requests for OIDC credential configuration type metadata",
parameters = @Parameter(name = "configurationId", in = ParameterIn.PATH, description = "Configuration ID"))
public ResponseEntity handle(final HttpServletRequest request, final HttpServletResponse response,
@PathVariable final String configurationId) {
val webContext = new JEEContext(request, response);
if (!getConfigurationContext().getIssuerService().validateIssuer(webContext, List.of(OidcConstants.VC_CREDENTIAL_TYPE_URL))) {
LOGGER.warn("CAS cannot accept the request given the issuer is invalid.");
val body = OAuth20Utils.getErrorResponseBody(OAuth20Constants.INVALID_REQUEST, "Invalid issuer");
return ResponseEntity.badRequest().body(body);
}
val body = metadataService.describeConfiguration(configurationId);
return body == null
? ResponseEntity.notFound().build()
: ResponseEntity.ok().body(body);
}
}
View on GitHub (pinned to e7288fc434)