Repository navigation
OIDC discovery advertises revocation_endpoint at /oauth2/revoke, but token revocation is routed at /oauth2/token/revoke #1195
Description
Describe the bug
Since #1058, the OpenID Connect discovery document (/oauth2/.well-known/openid-configuration) has advertised revocation_endpoint at <base>/revoke, but the token revocation resource is routed only at <base>/token/revoke. A client that takes the revocation URL from discovery calls an address that has no route, so token revocation fails.
The discovery URL is built in OAuth2UrisFactory:
OpenAM/openam-oauth2/src/main/java/org/forgerock/openam/oauth2/OAuth2UrisFactory.java
Lines 208 to 210 in 4d5cca0
| public String getRevocationEndpoint() { | |
| return baseUrl + "/revoke"; | |
| } |
public String getRevocationEndpoint() {
return baseUrl + "/revoke";
}The only route for TokenRevocationResource is in OAuth2RouterProvider:
OpenAM/openam-oauth2/src/main/java/org/forgerock/openam/oauth2/rest/OAuth2RouterProvider.java
Line 146 in 4d5cca0
| router.attach("/token/revoke", auditWithOAuthFilter(wrap(TokenRevocationResource.class))); |
router.attach("/token/revoke", auditWithOAuthFilter(wrap(TokenRevocationResource.class)));Nothing is attached at /revoke. The #1058 description assumed the endpoint already lived at /oauth2/revoke, but the admin guide (chap-oauth2.adoc, "/oauth2/token/revoke") and the developer guide (chap-client-dev.adoc) both document /oauth2/token/revoke, as did ForgeRock AM, and as PingAM still does. The same mismatch applies to subrealms, since both the discovery base URL and the router are realm-relative.
Affected releases: 16.1.2, 16.1.3 and 16.1.4. 16.1.1 does not advertise revocation_endpoint at all.
To Reproduce
- Get an access or refresh token for any OAuth 2.0 client.
GET https://openam.example.com:8443/openam/oauth2/.well-known/openid-configuration. The document contains"revocation_endpoint": "https://openam.example.com:8443/openam/oauth2/revoke".POSTthe token with the client credentials to thatrevocation_endpointURL. No route matches, and the token is not revoked.POSTthe same request tohttps://openam.example.com:8443/openam/oauth2/token/revoke. The token is revoked.
Expected behavior
revocation_endpoint in the discovery document points to the URL that actually revokes tokens: <base>/token/revoke, matching the documentation and PingAM. Clients and libraries that discover endpoints automatically then revoke tokens without extra configuration.
Suggested fix
Return the routed path from OAuth2UrisImpl:
public String getRevocationEndpoint() {
return baseUrl + "/token/revoke";
}Then add a test that compares revocation_endpoint (and ideally every other endpoint in the discovery document) with a path that OAuth2RouterProvider attaches. There are no tests for getRevocationEndpoint today. Attaching a second route at /revoke is not needed: the advertised URL has never worked, so no client can depend on it.
Found during the review of OpenIdentityPlatform/OpenIdentityPlatform.org#247, the PingAM 7.5 to OpenAM migration guide. The guide says the main OAuth 2.0 endpoints match PingAM when the context path is kept, and discovery-driven clients break on exactly this difference.
Activity