diff --git a/src/post_modules/ZXID/zxid.cmod b/src/post_modules/ZXID/zxid.cmod
index 1b934c1bdbc9bd4a69d0c88e3a553399f7a0bb30..48e5efb52c595f57be7678c6db138469c8d1ec75 100644
--- a/src/post_modules/ZXID/zxid.cmod
+++ b/src/post_modules/ZXID/zxid.cmod
@@ -48,6 +48,9 @@ DECLARATIONS
 /* Needed for zxid_new_at(). */
 #include <zxid/zxidpriv.h>
 
+/* Needed for zx_md_EntityDescriptor_s. */
+/* #include <zxid/zx-md-data.h> */
+
 #include "constants.h"
 
 #define THIS_OBJ Pike_interpreter.frame_pointer->current_object
@@ -761,21 +764,28 @@ static char* zxid_grab_domain_name(zxid_conf* cf, const char* url)
     stack_pop_n_elems_keep_top(args);
   }
 
-  PIKEFUN string(0..255) idp_list()
+  /*! Return a list of known identity providers.
+   *!
+   *! @returns
+   *!   Returns a mapping from IdP EID to display name (if any).
+   */
+  PIKEFUN mapping(string(0..255):string(0..255)) idp_list()
   {
-    int res_len = 0;
-    char *res = zxid_idp_list_cf_cgi(&THIS->conf, NULL, &res_len, 0);
-
-    push_string(make_shared_binary_string(res, res_len));
-
-    if (res_len) {
-      /* Note: zxd_idp_list_cf_cgi() returns an empty constant string
-       *       in some circumstances.
-       */
-      ZX_FREE(THIS->conf.ctx, res);
+    zxid_entity *idp = zxid_load_cot_cache(&THIS->conf);
+    int cnt = 0;
+    pop_n_elems(args);
+    check_stack(120);
+    while(idp) {
+      /* if (!idp->ed->IDPSSODescriptor) continue; */
+      push_text(idp->eid);
+      if (idp->dpy_name) {
+	push_text(idp->dpy_name);
+      } else {
+	push_constant_text("");
+      }
+      cnt++;
     }
-
-    stack_pop_n_elems_keep_top(args);
+    f_aggregate_mapping(cnt*2);
   }
 }
 /*! @endclass Configuration */