feat: add CAMELEER_OIDC_JWK_SET_URI for direct JWKS fetching
When set, fetches JWKs from this URL directly instead of discovering from the OIDC well-known endpoint. Needed when the public issuer URL (e.g., https://domain.com/oidc) isn't reachable from inside containers but the internal URL (http://logto:3001/oidc/jwks) is. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -155,17 +155,26 @@ public class SecurityConfig {
|
||||
private JwtDecoder buildOidcDecoder(SecurityProperties properties) throws Exception {
|
||||
String issuerUri = properties.getOidcIssuerUri();
|
||||
|
||||
// Discover JWKS URI and supported algorithms from OIDC discovery
|
||||
String discoveryUrl = issuerUri.endsWith("/")
|
||||
? issuerUri + ".well-known/openid-configuration"
|
||||
: issuerUri + "/.well-known/openid-configuration";
|
||||
URL url = new URI(discoveryUrl).toURL();
|
||||
OIDCProviderMetadata metadata;
|
||||
try (InputStream in = url.openStream()) {
|
||||
JSONObject json = (JSONObject) new JSONParser(JSONParser.DEFAULT_PERMISSIVE_MODE).parse(in);
|
||||
metadata = OIDCProviderMetadata.parse(json);
|
||||
// Resolve JWKS URI: use explicit config if set, otherwise discover from OIDC metadata.
|
||||
// Explicit URI is needed when the public issuer URL isn't reachable from inside
|
||||
// containers (e.g., https://domain.com/oidc) but the internal URL is (http://logto:3001/oidc/jwks).
|
||||
URL jwksUri;
|
||||
String jwkSetUri = properties.getOidcJwkSetUri();
|
||||
if (jwkSetUri != null && !jwkSetUri.isBlank()) {
|
||||
jwksUri = new URI(jwkSetUri).toURL();
|
||||
log.info("Using explicit JWKS URI: {}", jwksUri);
|
||||
} else {
|
||||
String discoveryUrl = issuerUri.endsWith("/")
|
||||
? issuerUri + ".well-known/openid-configuration"
|
||||
: issuerUri + "/.well-known/openid-configuration";
|
||||
URL url = new URI(discoveryUrl).toURL();
|
||||
OIDCProviderMetadata metadata;
|
||||
try (InputStream in = url.openStream()) {
|
||||
JSONObject json = (JSONObject) new JSONParser(JSONParser.DEFAULT_PERMISSIVE_MODE).parse(in);
|
||||
metadata = OIDCProviderMetadata.parse(json);
|
||||
}
|
||||
jwksUri = metadata.getJWKSetURI().toURL();
|
||||
}
|
||||
URL jwksUri = metadata.getJWKSetURI().toURL();
|
||||
|
||||
// Build decoder supporting ES384 (Logto default) and ES256, RS256
|
||||
var jwkSource = JWKSourceBuilder.create(jwksUri).build();
|
||||
|
||||
@@ -18,6 +18,7 @@ public class SecurityProperties {
|
||||
private String uiOrigin;
|
||||
private String jwtSecret;
|
||||
private String oidcIssuerUri;
|
||||
private String oidcJwkSetUri;
|
||||
private String oidcAudience;
|
||||
|
||||
public long getAccessTokenExpiryMs() { return accessTokenExpiryMs; }
|
||||
@@ -38,6 +39,8 @@ public class SecurityProperties {
|
||||
public void setJwtSecret(String jwtSecret) { this.jwtSecret = jwtSecret; }
|
||||
public String getOidcIssuerUri() { return oidcIssuerUri; }
|
||||
public void setOidcIssuerUri(String oidcIssuerUri) { this.oidcIssuerUri = oidcIssuerUri; }
|
||||
public String getOidcJwkSetUri() { return oidcJwkSetUri; }
|
||||
public void setOidcJwkSetUri(String oidcJwkSetUri) { this.oidcJwkSetUri = oidcJwkSetUri; }
|
||||
public String getOidcAudience() { return oidcAudience; }
|
||||
public void setOidcAudience(String oidcAudience) { this.oidcAudience = oidcAudience; }
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ security:
|
||||
ui-origin: ${CAMELEER_UI_ORIGIN:http://localhost:5173}
|
||||
jwt-secret: ${CAMELEER_JWT_SECRET:}
|
||||
oidc-issuer-uri: ${CAMELEER_OIDC_ISSUER_URI:}
|
||||
oidc-jwk-set-uri: ${CAMELEER_OIDC_JWK_SET_URI:}
|
||||
oidc-audience: ${CAMELEER_OIDC_AUDIENCE:}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user