{"record":{"id":"a6a9fc78110e4ddf","repo":"quarkusio/quarkus","slug":"tenant-restore-path-absolute-redirect-must-be-res","errorCode":null,"errorMessage":"/tenant-restore-path-absolute-redirect must be restored","messagePattern":"/tenant-restore-path-absolute-redirect must be restored","errorType":"http","errorClass":"RuntimeException","httpStatus":500,"severity":"error","filePath":"integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/TenantRestorePathAbsoluteRedirect.java","lineNumber":26,"sourceCode":"import io.quarkus.security.Authenticated;\n\n@Path(\"/tenant-restore-path-absolute-redirect\")\npublic class TenantRestorePathAbsoluteRedirect {\n\n    @Context\n    UriInfo ui;\n\n    @GET\n    @Authenticated\n    public String getTenant() {\n        return ui.getAbsolutePath().toString();\n    }\n\n    @GET\n    @Authenticated\n    @Path(\"/callback\")\n    public String getTenantCallback() {\n        throw new RuntimeException(\"/tenant-restore-path-absolute-redirect must be restored\");\n    }\n}\n","sourceCodeStart":8,"sourceCodeEnd":29,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/TenantRestorePathAbsoluteRedirect.java#L8-L29","documentation":"This RuntimeException is thrown intentionally by the /callback endpoint of the TenantRestorePathAbsoluteRedirect test resource. In Quarkus OIDC code-flow tests, the callback endpoint should never be reached after a successful login because the restore-path mechanism must redirect the user back to the original requested path (/tenant-restore-path-absolute-redirect) before the callback is invoked. Hitting the endpoint means the OIDC restore-path/absolute-redirect flow failed to restore the original URL.","triggerScenarios":"GET /tenant-restore-path-absolute-redirect/callback is invoked, i.e. the OIDC authorization-code callback landed on the callback endpoint instead of redirecting back to the originally requested path with an absolute redirect.","commonSituations":"OIDC code-flow configuration changes (quarkus.oidc.restore-path-after-redirect / redirect-path handling), Keycloak/WireMock test-server changes altering redirect URLs, or regressions in Quarkus OIDC's restore-path behavior for absolute redirects.","solutions":["Verify the OIDC code-flow configuration restores the original path (restore-path-after-redirect enabled and correct callback path configured).","Check that the initial request path /tenant-restore-path-absolute-redirect is protected by the correct tenant and that the state cookie carries the restore path.","Inspect server logs for the OIDC redirect Location header; confirm it is absolute and points back to the original path.","Re-run with quarkus.log.category.io.quarkus.oidc set to DEBUG to trace the redirect decisions."],"exampleFix":"// before (flow broken, callback reached)\n@GET @Authenticated @Path(\"/callback\")\npublic String getTenantCallback() {\n    throw new RuntimeException(\"/tenant-restore-path-absolute-redirect must be restored\");\n}\n// after (correct flow: OIDC redirects back to the original path before the callback is ever hit;\n// if the callback is legitimately reached, return the expected restored content instead)\n@GET @Authenticated @Path(\"/callback\")\npublic String getTenantCallback() {\n    return \"callback-reached\"; // only valid when restore-path intentionally routes here\n}","handlingStrategy":"validation","validationCode":"if (requestPath.endsWith(\"/callback\") && !oidcRestoredOriginalPath(request)) {\n    throw new IllegalStateException(\"OIDC restore-path did not redirect back to the original path\");\n}","typeGuard":"boolean isRestoredPathRedirect(Response resp) {\n    return resp.getStatusInfo().getFamily() == Response.Status.Family.REDIRECT\n            && resp.getLocation() != null\n            && resp.getLocation().isAbsolute();\n}","tryCatchPattern":"try {\n    String body = given().redirects().follow(false).get(path).asString();\n} catch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"must be restored\")) {\n        // restore-path failed; inspect OIDC redirect configuration\n    }\n    throw e;\n}","preventionTips":["Assert in tests that the first response to a protected path is an absolute redirect back to that path, not the callback.","Keep OIDC callback path and restore-path config in sync across environments.","Trace Location headers with DEBUG logging on io.quarkus.oidc during code-flow changes."],"tags":["oidc","code-flow","redirect","integration-test"],"backgroundTag":"oidc-restore-path-redirect","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}