8000 Compliant with RFC8414, return server metadata at /.well-known/oauth-authorization-server/realms/{realm} by tnorimat · Pull Request #41440 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content

Compliant with RFC8414, return server metadata at /.well-known/oauth-authorization-server/realms/{realm} - #41440

Merged
ahus1 merged 1 commit into
keycloak:mainfrom
Hitachi:ISSUE-40923
Sep 3, 2025
Merged

ahus1 merged 1 commit into
keycloak:mainfrom
Hitachi:ISSUE-40923

Conversation

@tnorimat
Copy link
Copy Markdown
Contributor

closes #40923

@tnorimat
Copy link
Copy Markdown
Contributor Author

@mposolda Hello,
The issue is related to Model Context Protocol support: #41521 .
If possible, I would appreciate it if you could check the PR.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @tnorimat - I am jumping in because a very identical change is required by OpenID4VCI Draft 16 as we will need /.well-known/openid-credential-issuer/realms/{realm}.

https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0-16.html#name-credential-issuer-metadata-

Credential Issuers publishing metadata MUST make a JSON document available at the path formed inserting the string /.well-known/openid-credential-issuer into the Credential Issuer Identifier between the host component and the path component, if any.

For example, the metadata for the Credential Issuer Identifier https://issuer.example.com/tenant would be retrieved from https://issuer.example.com/.well-known/openid-credential-issuer/tenant. The metadata for the Credential Issuer Identifier https://tenant.issuer.example.com would be retrieved from https://tenant.issuer.example.com/.well-known/openid-credential-issuer.

Could this PR take into account extensibility regarding well-known resources in general? I mean something close to the suggestion of @thomasdarimont here: https://cloud-native.slack.com/archives/C05KR0TL4P8/p1752669894360769?thread_ts=1752669762.102799&cid=C05KR0TL4P8 ?

@Path(".well-known")
public class WellKnownRootResource {

    protected static final Logger logger = Logger.getLogger(WellKnownRootResource.class);

    @Context
    protected KeycloakSession session;

    @GET
    @Path("/{providerId}/realms/{realmName}")
    public Response getWellKnown(@PathParam("providerId") String providerId, @PathParam("realmName") String realmName) {

        RealmModel realm = session.realms().getRealmByName(realmName);
        if (realm == null) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }

        session.getContext().setRealm(realm);
        WellKnownProvider knownProvider = session.getProvider(WellKnownProvider.class, providerId);
        if (knownProvider == null) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }

        Object config = knownProvider.getConfig();
        return Response.ok(config).build();
    }
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@IngridPuppet Hello, thank you for the feedback comment. I will incorporate the extensibility you suggested.

@tnorimat
tnorimat force-pushed the ISSUE-40923 branch 6 times, most recently from c6d1606 to cb77869 Compare July 31, 2025 06:57
@tnorimat
Copy link
Copy Markdown
Contributor Author

@IngridPuppet I've revised the PR. Would it suit your purposes?

@IngridPuppet IngridPuppet left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for updating the PR for extensibility. By adding IDs of WellKnownProvider's to the validProviderList array, we should have the correct endpoints automatically available. Additionally, I checked all the changes and agree with them.

@tnorimat
tnorimat force-pushed the ISSUE-40923 branch 2 times, most recently from ef87f1b to 0e9b967 Compare August 1, 2025 03:22
@tnorimat
tnorimat commented Aug 1, 2025
Copy link
Copy Markdown
Contributor Author

@IngridPuppet I slightly modified the codes. OID4VCI is an experimental feature, so we need to consider that to publish OID4VCI'S metadata.

    private boolean isValidProvider(String providerName) {
        // you can add codes here considering the current status of the implementation (preview, experimental).
        if (OAuth2WellKnownProviderFactory.PROVIDER_ID.equals(providerName)) return true;
        return false;
    }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need that Path("/") annotation here? Since it is the root entry point it might lead to conflicts with other resource handlers.

@tnorimat tnorimat Aug 21, 2025 •
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thomasdarimont Thank you for the comment. Yes, both root resource classes WelcomeResources and ServerMetadataResource have the same path annotation value /. To avoid this duplication, I modified as follows:

@Path("/.well-known")
public class ServerMetadataResource {

    protected static final Logger logger = Logger.getLogger(ServerMetadataResource.class);

    @Context
    protected KeycloakSession session;

    @OPTIONS
    @Path("{provider}/realms/{realm}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getOAuth2AuthorizationServerWellKnownVersionPreflight(final @PathParam("provider") String providerName,
                                                                          final @PathParam("realm") String name) {
        if (!isValidProvider(providerName)) throw new NotFoundException();
        return Cors.builder().allowedMethods("GET").preflight().auth().add(Response.ok());
    }

    @GET
    @Path("{provider}/realms/{realm}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getOAuth2AuthorizationServerWellKnown(final @PathParam("provider") String providerName,
                                                          final @PathParam("realm") String name) {
        if (!isValidProvider(providerName)) throw new NotFoundException();
        return RealmsResource.getWellKnownResponse(session, name, providerName, logger);
    }

…authorization-server/realms/{realm}

closes keycloak#40923

Signed-off-by: Takashi Norimatsu <takashi.norimatsu.ws@hitachi.com>
@thomasdarimont
thomasdarimont commented Aug 22, 2025 •
Copy link
Copy Markdown
Contributor

I just noticed that this only works as expected if Keycloak is configured with an empty context path.
An empty context path is the current default, but existing deployments are probably still using a context path like /auth or similar.

I don't know if it is possible to configure Keycloak to always listen on "/" for some requests despite the context path setting but if not we should document that users might need to use a reverse-proxy in front of Keycloak to route the /.well-known requests internally to the proper endpoint.

The following nginx configuration works for me:

        # https://id.acme.test/.well-known/ssf-configuration/auth/realms/ssf-demo
        # /.well-known/ssf-configuration/<realmpath>  ->  http://keycloak/<realmpath>/ssf/.well-known/ssf-configuration
        location ~ ^/\.well-known/ssf-configuration/(?<realmpath>.+)$ {
            proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-Host  $host;
            proxy_set_header X-Forwarded-Port  $server_port;

            proxy_connect_timeout 2s;

            proxy_buffer_size       128k;
            proxy_buffers           4 256k;
            proxy_busy_buffers_size 256k;

            proxy_pass http://keycloak/$realmpath/ssf/.well-known/ssf-configuration$is_args$args;
        }

@VinodAnandan
Copy link
Copy Markdown
Contributor

@tnorimat @thomasdarimont @mposolda @stianst Would you be able to help this PR? Are there any significant concerns or blockers apart from the documentation? This PR is important for MCP and OID4VCI, and it is currently blocking the following issue: #41589

Cc : @Ogenbertrand @francis-pouatcha @IngridPuppet

@thomasdarimont
Copy link
Copy Markdown
Contributor

FYI I created this issue in the quarkus repository #41440 to discuss additional solutions to serve resources on the context-root even if a custom context path is used.

@ahus1 ahus1 left a comment •
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've reviewed this PR, and aligned it with the RFCs contents. Some docs update might be missing, and I'll open a follow-up issue for that.

I also reviewed the previous comments. While I see that this won't work with the /auth prefix, this shouldn't keep us from merging this PR as is.

@ahus1
ahus1 merged commit ea63cdc into keycloak:main Sep 3, 2025
@ahus1
ahus1 commented Sep 3, 2025 •
Copy link
Copy Markdown
Member

Follow-up docs task: #42323

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Compliant with RFC8414, return server metadata at /.well-known/oauth-authorization-server/realms/{realm}

5 participants

0