Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package sso-mib for openSUSE:Factory checked 
in at 2026-03-18 16:50:18
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/sso-mib (Old)
 and      /work/SRC/openSUSE:Factory/.sso-mib.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "sso-mib"

Wed Mar 18 16:50:18 2026 rev:2 rq:1340875 version:0.8.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/sso-mib/sso-mib.changes  2026-03-11 
20:52:26.830843533 +0100
+++ /work/SRC/openSUSE:Factory/.sso-mib.new.8177/sso-mib.changes        
2026-03-18 16:51:48.676305614 +0100
@@ -1,0 +2,8 @@
+Tue Mar 17 23:50:08 UTC 2026 - Luca Boccassi <[email protected]>
+
+- Import version 0.8.0
+  This release adds support for v2.0.2+ MSFT broker versions and adds
+  JSON output for sso-mib-tool commands. Along that, many minor bugs
+  in the library have been fixed.
+
+-------------------------------------------------------------------

Old:
----
  sso-mib-0.7.0.tar.gz

New:
----
  sso-mib-0.8.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ sso-mib.spec ++++++
--- /var/tmp/diff_new_pack.06v7l8/_old  2026-03-18 16:51:49.500339577 +0100
+++ /var/tmp/diff_new_pack.06v7l8/_new  2026-03-18 16:51:49.504339743 +0100
@@ -18,7 +18,7 @@
 %global soversion 0
 
 Name:           sso-mib
-Version:        0.7.0
+Version:        0.8.0
 Release:        1%{?dist}
 Summary:        Tools and library for Single-Sign-On with CA for Entra via 
Himmelblau
 

++++++ sso-mib-0.7.0.tar.gz -> sso-mib-0.8.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/.github/workflows/build.yml 
new/sso-mib-0.8.0/.github/workflows/build.yml
--- old/sso-mib-0.7.0/.github/workflows/build.yml       2025-11-06 
16:00:28.000000000 +0100
+++ new/sso-mib-0.8.0/.github/workflows/build.yml       2026-03-17 
10:52:48.000000000 +0100
@@ -15,6 +15,10 @@
 permissions:
   contents: read
 
+env:
+  LIBJWT3_VERSION: "3.2.3"
+  LIBJWT3_SHA256: 
c6d8a4ead0321317937cc29d8ebc5be48d114d02e007711bb2d4cca5d2a6d713
+
 jobs:
   reuse-and-codestyle:
     runs-on: ubuntu-24.04
@@ -84,9 +88,16 @@
           fetch-depth: 0
       - name: install dependencies
         run: |
+          if [[ "${{ matrix.distro }}" == "debian:bookworm" ]]; then
+            # Add backports repository for Debian bookworm
+            echo "deb http://deb.debian.org/debian bookworm-backports main" > 
/etc/apt/sources.list.d/backports.list
+            echo -e "Package: meson\nPin: release 
n=bookworm-backports\nPin-Priority: 501" | \
+              tee /etc/apt/preferences.d/meson-backports.pref > /dev/null
+          fi
           apt-get update
-          apt-get install -y --no-install-recommends devscripts equivs
+          apt-get install -y --no-install-recommends devscripts equivs meson
           mk-build-deps --install -t "apt-get --no-install-recommends -y"
+        shell: bash
       - name: build package
         run: |
           dpkg-buildpackage -us -uc -b
@@ -106,7 +117,41 @@
           subject-path: |
             linux-amd64-deb/*.deb
 
+  build-with-libjwt3:
+    runs-on: ubuntu-24.04
+    container: "debian:trixie"
+    steps:
+      - name: checkout repository
+        uses: actions/checkout@v4
+        with:
+          fetch-depth: 0
+      - name: install dependencies
+        run: |
+          apt-get update
+          apt-get install -y --no-install-recommends \
+            build-essential meson cmake ninja-build curl ca-certificates \
+            libjansson-dev libssl-dev \
+            libgio-2.0-dev libjson-glib-dev libdbus-1-dev uuid-dev
+      - name: build libjwt3
+        run: |
+          curl -L -q 
https://github.com/benmcollins/libjwt/releases/download/v${LIBJWT3_VERSION}/libjwt-${LIBJWT3_VERSION}.tar.xz
 \
+            > /tmp/libjwt-${LIBJWT3_VERSION}.tar.xz
+          echo "$LIBJWT3_SHA256 /tmp/libjwt-${LIBJWT3_VERSION}.tar.xz" | 
sha256sum -c
+          WORKDIR=$(pwd)
+          cd /tmp
+          tar -xf libjwt-${LIBJWT3_VERSION}.tar.xz
+          cd libjwt-${LIBJWT3_VERSION}
+          cmake -B build -GNinja
+          cmake --build build
+          cmake --install build
+          cd $WORKDIR
+      - name: build sso-mib-tool
+        run: | 
+          meson -Dlibjwt=enabled build
+          cd build && ninja sso-mib-tool
+
   deploy:
+    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
     runs-on: ubuntu-24.04
     needs: build
     permissions:
@@ -117,6 +162,5 @@
       url: ${{ steps.deployment.outputs.page_url }}
     steps:
       - name: Deploy API docs
-        if: github.ref == 'refs/heads/main'
         id: deployment
         uses: actions/deploy-pages@v4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/README.md new/sso-mib-0.8.0/README.md
--- old/sso-mib-0.7.0/README.md 2025-11-06 16:00:28.000000000 +0100
+++ new/sso-mib-0.8.0/README.md 2026-03-17 10:52:48.000000000 +0100
@@ -2,7 +2,8 @@
 
 # Single-Sign-On using Microsoft Identity Broker (SSO-MIB)
 
-This project implements a C library to interact with a locally running 
microsoft-identity-broker to get various authentication tokens via DBus.
+sso-mib is a lightweight C library and CLI tool for interacting with a 
Microsoft Identity Broker to obtain authentication tokens via DBus.
+
 By that, it implements support for the OIDC extension [MS-OAPXBC], sections 
[3.1.5.1.2 Request for Primary Refresh 
Token](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-oapxbc/d32d5cd0-05d4-4ec2-8bcc-ac29ce711c23),
 [3.1.5.1.3 Exchange Primary Refresh Token for Access 
Token](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-oapxbc/06e2bf0d-8cea-4b11-ad78-d212330ebda9)
 and can be used to obtain Proof-of-Possession tokens for RDP 
[[MS-RDPBCGR](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/e967ebeb-9e9f-443e-857a-5208802943c2)].
 
@@ -12,6 +13,7 @@
 - JSON-Glib
 - libdbus
 - libuuid
+- libjwt (only for sso-mib-tool)
 
 ## Interface
 
@@ -32,8 +34,8 @@
 ```c
 #include <sso-mib/sso-mib.h>
 
-const gchar* client_id = "<my-client-uuid>";
-const gchar* authority = MIB_AUTHORITY_COMMON;
+const gchar *client_id = "<my-client-uuid>";
+const gchar *authority = MIB_AUTHORITY_COMMON;
 
 MIBClientApp *app = mib_public_client_app_new(client_id, authority, NULL, 
NULL);
 GSList *scopes = NULL;
@@ -49,8 +51,8 @@
 MIBPrtSsoCookie *prt_cookie =
     mib_client_app_acquire_prt_sso_cookie(app, account, MIB_SSO_URL_DEFAULT, 
scopes);
 
-const char * name  = mib_prt_sso_cookie_get_name(cookie);
-const char * value = mib_prt_sso_cookie_get_content(cookie);
+const char *name = mib_prt_sso_cookie_get_name(cookie);
+const char *value = mib_prt_sso_cookie_get_content(cookie);
 ```
 
 Further examples are provided in `examples`.
@@ -59,6 +61,16 @@
 
 The `sso-mib-tool` provides a simple frontend to interact with the library.
 
+For example, the following can be used to obtain a token for sending mail via 
SMTP:
+
+```bash
+$ sso-mib-tool acquireTokenInteractive -f json \
+    -s <client_id> \
+    -r https://login.microsoftonline.com/common/oauth2/nativeclient \
+    -x <authority> \
+    -S offline_access -S 'https://outlook.office365.com/SMTP.Send'
+```
+
 ## Maintainers
 
 - Felix Moessbauer <[email protected]>
@@ -70,6 +82,10 @@
 
 - `AF73F6EF5A53CFE304569F50E648A311F67A50FC` (Felix Moessbauer)
 
+Since version `v0.8`, the following keys are used:
+
+    3785ED68D0F83B7BD7D23D7FE1136CEB2754A0BD (Felix Moessbauer)
+
 ## License
 
 The library is licensed according to the terms of the GNU Lesser General 
Public License v2.1.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/debian/changelog 
new/sso-mib-0.8.0/debian/changelog
--- old/sso-mib-0.7.0/debian/changelog  2025-11-06 16:00:28.000000000 +0100
+++ new/sso-mib-0.8.0/debian/changelog  2026-03-17 10:52:48.000000000 +0100
@@ -1,3 +1,9 @@
+sso-mib (0.8.0) unstable; urgency=medium
+
+  * Update to 0.8.0 release
+
+ -- Felix Moessbauer <[email protected]>  Tue, 17 Mar 2026 10:45:07 
+0100
+
 sso-mib (0.7.0) unstable; urgency=medium
 
   * add git credential helper for SMTP on O365
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/examples/avatar/main.c 
new/sso-mib-0.8.0/examples/avatar/main.c
--- old/sso-mib-0.7.0/examples/avatar/main.c    2025-11-06 16:00:28.000000000 
+0100
+++ new/sso-mib-0.8.0/examples/avatar/main.c    2026-03-17 10:52:48.000000000 
+0100
@@ -53,6 +53,7 @@
 {
        const gchar *client_id = EDGE_BROWSER_CLIENT_ID;
        const gchar *authority = MIB_AUTHORITY_COMMON;
+       int ret = 0;
 
        MIBClientApp *app =
                mib_public_client_app_new(client_id, authority, NULL, NULL);
@@ -70,24 +71,29 @@
        FILE *f = fopen("avatar.jpg", "w");
        if (!f) {
                g_printerr("could not open file\n");
-               g_slist_free_full(accounts, (GDestroyNotify)g_object_unref);
-               g_object_unref(app);
-               return -1;
+               ret = -1;
+               goto cleanup;
        }
 
        printf("Acquire Bearer token\n");
-       scopes = g_slist_append(scopes, g_strdup(MIB_SCOPE_GRAPH_DEFAULT));
+       scopes = g_slist_append(scopes, g_strdup("User.Read"));
        MIBPrt *prt =
                mib_client_app_acquire_token_silent(app, account, scopes, NULL, 
NULL, NULL);
+       if (!prt) {
+               printf("Failed to get Graph API token\n");
+               ret = -1;
+               goto cleanup;
+       }
+
        const char *token = mib_prt_get_access_token(prt);
        fetch_avatar(token, f);
-       fclose(f);
        printf("Successfully stored avatar picture in 'avatar.jpg'\n");
 
-       /* cleanup */
+cleanup:
+       fclose(f);
        g_slist_free_full(scopes, (GDestroyNotify)g_free);
        g_slist_free_full(accounts, (GDestroyNotify)g_object_unref);
-       g_object_unref(prt);
+       g_clear_object(&prt);
        g_object_unref(app);
-       return 0;
+       return ret;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/examples/onedrive/main.c 
new/sso-mib-0.8.0/examples/onedrive/main.c
--- old/sso-mib-0.7.0/examples/onedrive/main.c  2025-11-06 16:00:28.000000000 
+0100
+++ new/sso-mib-0.8.0/examples/onedrive/main.c  2026-03-17 10:52:48.000000000 
+0100
@@ -136,10 +136,7 @@
                goto cleanup;
 
        mib_client_app_set_redirect_uri(app, APP_REDIRECT_URI);
-       scopes = g_slist_append(scopes, "Files.ReadWrite");
-       scopes = g_slist_append(scopes, "Files.ReadWrite.All");
-       scopes = g_slist_append(scopes, "Sites.ReadWrite.All");
-       scopes = g_slist_append(scopes, "offline_access");
+       scopes = g_slist_append(scopes, "Files.Read");
 
        token = mib_client_app_acquire_token_interactive(
                app, scopes, MIB_PROMPT_UNSET, upn_hint, NULL, NULL, NULL);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/include/mib-prt.h 
new/sso-mib-0.8.0/include/mib-prt.h
--- old/sso-mib-0.7.0/include/mib-prt.h 2025-11-06 16:00:28.000000000 +0100
+++ new/sso-mib-0.8.0/include/mib-prt.h 2026-03-17 10:52:48.000000000 +0100
@@ -12,7 +12,6 @@
 #include <glib-object.h>
 
 #include "mib-exports.h"
-#include "mib-prt.h"
 #include "mib-pop-params.h"
 
 /**
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/meson.build 
new/sso-mib-0.8.0/meson.build
--- old/sso-mib-0.7.0/meson.build       2025-11-06 16:00:28.000000000 +0100
+++ new/sso-mib-0.8.0/meson.build       2026-03-17 10:52:48.000000000 +0100
@@ -3,10 +3,11 @@
 project(
   'sso-mib',
   'c',
-  version : '0.7.0',
-  default_options : ['c_std=c11', 'warning_level=3'],
+  version : '0.8.0',
+  default_options : ['c_std=gnu11', 'warning_level=3'],
 )
 project_description = 'Library to interact with the Microsoft Device Broker 
for SSO'
+add_project_arguments('-Wno-unused-parameter', language : 'c')
 
 libsso_mib_hdrs = [
   'include/sso-mib.h',
@@ -38,17 +39,26 @@
 giodep = dependency('gio-2.0')
 jsondep = dependency('json-glib-1.0')
 uuiddep = dependency('uuid')
-jwtdep = dependency('libjwt')
+jwtdep = dependency('libjwt', required: get_option('libjwt'))
+
+summary({'libjwt (sso-mib-tool)': jwtdep.found()}, bool_yn: true, section: 
'Misc dependencies')
 
 identity_broker = gnome.gdbus_codegen('identity-broker',
   sources: 'dbus/spec/com.microsoft.identity.broker1.xml',
   interface_prefix : 'com.microsoft.',
   namespace : 'mib_dbus',
 )
+identity_broker_obj = static_library(
+  'identity_broker_obj',
+  identity_broker,
+  c_args : ['-Wno-pedantic'],
+  gnu_symbol_visibility : 'hidden',
+  dependencies : [giodep],
+  install : false)
 
 libsso_mib = shared_library(
   meson.project_name(),
-  libsso_mib_src, identity_broker,
+  libsso_mib_src, identity_broker[1],
   install : true,
   c_args : ['-DBUILDING_SSO_MIB=1',
             '-DSSO_MIB_COMPILATION=1',
@@ -56,6 +66,7 @@
   gnu_symbol_visibility : 'hidden',
   include_directories : public_headers,
   dependencies : [giodep, glibdep, jsondep, uuiddep],
+  link_with : [identity_broker_obj],
   version : meson.project_version(),
   soversion : '0',
 )
@@ -70,6 +81,16 @@
   requires: ['glib-2.0', 'gio-2.0', 'uuid']
 )
 
+sso_mib_tool_cargs_extra = []
+if jwtdep.found()
+  jwtdep_version = jwtdep.version().split('.')
+  sso_mib_tool_cargs_extra += [
+    '-DWITH_LIBJWT',
+    '-DLIBJWT_VERSION_MAJOR=' + jwtdep_version[0],
+    '-DLIBJWT_VERSION_MINOR=' + jwtdep_version[1],
+  ]
+endif
+
 sso_mib_tool = executable(
   'sso-mib-tool',
   [
@@ -78,6 +99,7 @@
   install : true,
   include_directories : public_headers,
   link_with : [libsso_mib],
+  c_args: sso_mib_tool_cargs_extra,
   dependencies: [glibdep, giodep, jsondep, uuiddep, jwtdep],
   install_tag : 'tool'
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/meson_options.txt 
new/sso-mib-0.8.0/meson_options.txt
--- old/sso-mib-0.7.0/meson_options.txt 2025-11-06 16:00:28.000000000 +0100
+++ new/sso-mib-0.8.0/meson_options.txt 2026-03-17 10:52:48.000000000 +0100
@@ -8,3 +8,7 @@
        type: 'boolean',
        value: false,
        description: 'Build the examples [default=false]')
+option('libjwt',
+       description: 'Enable code that depends on libjwt',
+       type: 'feature',
+       value: 'auto')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/src/mib-account.c 
new/sso-mib-0.8.0/src/mib-account.c
--- old/sso-mib-0.7.0/src/mib-account.c 2025-11-06 16:00:28.000000000 +0100
+++ new/sso-mib-0.8.0/src/mib-account.c 2026-03-17 10:52:48.000000000 +0100
@@ -24,7 +24,7 @@
 
 static void mib_account_finalize(GObject *gobject)
 {
-       MIBAccount *self = 
mib_account_get_instance_private(MIB_ACCOUNT(gobject));
+       MIBAccount *self = MIB_ACCOUNT(gobject);
        g_clear_pointer(&self->client_info, g_free);
        g_clear_pointer(&self->environment, g_free);
        g_clear_pointer(&self->family_name, g_free);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/src/mib-client-app.c 
new/sso-mib-0.8.0/src/mib-client-app.c
--- old/sso-mib-0.7.0/src/mib-client-app.c      2025-11-06 16:00:28.000000000 
+0100
+++ new/sso-mib-0.8.0/src/mib-client-app.c      2026-03-17 10:52:48.000000000 
+0100
@@ -6,7 +6,6 @@
 #include "identity-broker.h"
 #include "mib-account-impl.h"
 #include "mib-client-app-impl.h"
-#include "mib-account-impl.h"
 #include "mib-pop-params-impl.h"
 #include "mib-prt-impl.h"
 #include "mib-prt-sso-cookie-impl.h"
@@ -16,12 +15,32 @@
 #define DBUS_BROKER_PATH "/com/microsoft/identity/broker1"
 
 // according to 
https://msal-python.readthedocs.io/en/latest/#publicclientapplication
-#define MIB_MS_BROKER_REDIRECT_URI_FMT \
-       "ms-appx-web://Microsoft.AAD.BrokerPlugin/%s"
+#define MIB_MS_BROKER_REDIRECT_URI \
+       "https://login.microsoftonline.com/common/oauth2/nativeclient";
 
 // MSAL does not define any lower-bound (yet)
 #define MIB_REQUIRED_BROKER_PROTOCOL_VERSION "0.0"
 
+/*
+ * Values from MSAL runtime (internal interface)
+ */
+enum AuthorizationType {
+       AT_NONE = 0,
+       AT_CACHED_REFRESH_TOKEN = 1,
+       AT_IMPORTED_REFRESH_TOKEN = 2,
+       AT_USERNAME_PASSWORD = 3,
+       AT_WINDOWS_INTEGRATED_AUTH = 4,
+       AT_AUTH_CODE = 5,
+       AT_INTERACTIVE = 6,
+       AT_CERTIFICATE = 7,
+       AT_PRT_SSO_COOKIE = 8,
+       AT_COMPLETE_BROKER_RESULT = 9,
+       AT_DEVICE_INFO_REQUEST = 10,
+       AT_SIGN_OUT_INTERACTIVE = 11,
+       AT_SIGN_OUT_SILENT = 12,
+       AT_ACCOUNT_TRANSFER = 13
+};
+
 struct _MIBClientApp {
        GObject parent_instance;
 
@@ -39,13 +58,9 @@
 
 static void mib_client_app_finalize(GObject *gobject)
 {
-       MIBClientApp *priv =
-               mib_client_app_get_instance_private(MIB_CLIENT_APP(gobject));
+       MIBClientApp *priv = MIB_CLIENT_APP(gobject);
        g_clear_object(&priv->cancellable);
        g_clear_object(&priv->broker);
-       if (priv->cancellable) {
-               g_clear_object(&priv->cancellable);
-       }
        g_clear_pointer(&priv->authority, g_free);
        g_clear_pointer(&priv->redirect_uri, g_free);
        G_OBJECT_CLASS(mib_client_app_parent_class)->finalize(gobject);
@@ -160,6 +175,10 @@
        return accounts;
 }
 
+/**
+ * If no upn is provided, return the first account.
+ * On error or when the no account has a matching upn return null.
+ */
 static JsonObject *mib_client_app_get_account_by_upn_raw(MIBClientApp *app,
                                                                                
                                 const gchar *upn)
 {
@@ -174,21 +193,24 @@
                goto err;
        }
        for (guint i = 0; i < json_array_get_length(accounts_array); i++) {
-               account = json_array_get_object_element(accounts_array, i);
+               JsonObject *_account = 
json_array_get_object_element(accounts_array, i);
                if (!upn) {
                        g_debug("no upn provided");
+                       account = _account;
                        break;
                }
-               if (!json_object_has_member(account, "username"))
-                       break;
+               if (!json_object_has_member(_account, "username"))
+                       continue;
                const gchar *username =
-                       json_object_get_string_member(account, "username");
+                       json_object_get_string_member(_account, "username");
                if (g_strcmp0(username, upn) == 0) {
                        g_debug("account matching UPN found");
+                       account = _account;
                        break;
                }
        }
-       json_object_ref(account);
+       if (account)
+               json_object_ref(account);
 err:
        json_object_unref(accounts);
        return account;
@@ -217,10 +239,10 @@
                        g_warning("error parsing account data");
                        break;
                }
-               accounts_list = g_slist_append(accounts_list, mib_account);
+               accounts_list = g_slist_prepend(accounts_list, mib_account);
        }
        json_object_unref(accounts);
-       return accounts_list;
+       return g_slist_reverse(accounts_list);
 }
 
 MIBAccount *mib_client_app_get_account_by_upn(MIBClientApp *app,
@@ -267,7 +289,7 @@
 gchar *mib_client_app_get_broker_redirect_uri(const MIBClientApp *self)
 {
        g_assert(self);
-       return g_strdup_printf(MIB_MS_BROKER_REDIRECT_URI_FMT, self->client_id);
+       return g_strdup(MIB_MS_BROKER_REDIRECT_URI);
 }
 
 void mib_client_app_set_redirect_uri(MIBClientApp *self, const gchar *uri)
@@ -336,16 +358,18 @@
        g_assert(app);
        g_assert(msal_cpp_version);
 
-       JsonObject *version_json;
-       gchar *version;
+       JsonObject *version_json = NULL;
+       gchar *version = NULL;
        version_json = mib_get_linux_broker_version_raw(app, msal_cpp_version);
        if (!version_json ||
                !json_object_has_member(version_json, "linuxBrokerVersion")) {
-               return NULL;
+               goto err;
        }
        version = g_strdup(
                json_object_get_string_member(version_json, 
"linuxBrokerVersion"));
-       json_object_unref(version_json);
+err:
+       if (version_json)
+               json_object_unref(version_json);
        return version;
 }
 
@@ -353,20 +377,21 @@
 prepare_prt_auth_params(MIBClientApp *app, JsonObject *account,
                                                JsonArray *scopes, const gchar 
*claims_challenge,
                                                JsonObject *auth_scheme, const 
gchar *renew_token,
-                                               JsonObject *extra_params)
+                                               JsonObject *extra_params, const 
gchar *sso_url,
+                                               enum AuthorizationType 
auth_type)
 {
        // {
        //  'accessTokenToRenew': renew_token,
        //  'account': account,
        //  'authority': context['authority']
-       //  'authorizationType': 8,  # OAUTH2
+       //  'authorizationType': 8 (cookie with sso_url), 1 otherwise
        //  'clientId': client_id,
        //  'redirectUri':
        //  '<context['authority']>/oauth2/nativeclient',
        //  'requestedScopes': ["https://graph.microsoft.com/.default";],
        //  'username': account['username'],
+       //  'ssoUrl': sso_url,
        // }
-
        JsonNode *account_node = json_node_new(JSON_NODE_OBJECT);
        json_node_set_object(account_node, account);
        JsonNode *scopes_node = json_node_new(JSON_NODE_ARRAY);
@@ -384,7 +409,7 @@
        json_builder_set_member_name(builder, "authority");
        json_builder_add_string_value(builder, 
mib_client_app_get_authority(app));
        json_builder_set_member_name(builder, "authorizationType");
-       json_builder_add_int_value(builder, 8); // OAUTH2
+       json_builder_add_int_value(builder, auth_type);
        json_builder_set_member_name(builder, "clientId");
        json_builder_add_string_value(builder, 
mib_client_app_get_client_id(app));
        if (claims_challenge) {
@@ -410,6 +435,10 @@
        json_builder_add_value(builder, scopes_node);
        json_builder_set_member_name(builder, "username");
        json_builder_add_string_value(builder, username);
+       if (sso_url) {
+               json_builder_set_member_name(builder, "ssoUrl");
+               json_builder_add_string_value(builder, sso_url);
+       }
        json_builder_end_object(builder);
 
        JsonNode *root = json_builder_get_root(builder);
@@ -430,15 +459,13 @@
        gboolean ok;
        JsonObject *token;
        JsonObject *auth_params = prepare_prt_auth_params(
-               app, account, scopes, claims_challenge, auth_scheme, 
renew_token, NULL);
+               app, account, scopes, claims_challenge, auth_scheme, 
renew_token, NULL,
+               NULL, AT_CACHED_REFRESH_TOKEN);
        JsonNode *auth_params_node = json_node_new(JSON_NODE_OBJECT);
        json_node_set_object(auth_params_node, auth_params);
        json_object_unref(auth_params);
 
        JsonObject *params_obj = json_object_new();
-       JsonNode *account_node = json_node_new(JSON_NODE_OBJECT);
-       json_node_set_object(account_node, account);
-       json_object_set_member(params_obj, "account", account_node);
        json_object_set_member(params_obj, "authParameters", auth_params_node);
        debug_print_json_object("mib_acquire_token_silent_raw", "request",
                                                        params_obj);
@@ -486,7 +513,7 @@
        if (!token_json) {
                return NULL;
        }
-       MIBPrt *token = mib_prt_from_json(token_json);
+       MIBPrt *token = mib_prt_from_json(token_json, account);
        json_object_unref(token_json);
        return token;
 }
@@ -502,9 +529,9 @@
        gboolean ok;
        JsonObject *token;
 
-       JsonObject *auth_params =
-               prepare_prt_auth_params(app, account, scopes, claims_challenge,
-                                                               auth_scheme, 
NULL, extra_params);
+       JsonObject *auth_params = prepare_prt_auth_params(
+               app, account, scopes, claims_challenge, auth_scheme, NULL, 
extra_params,
+               NULL, AT_INTERACTIVE);
 
        /* TODO: check if this is the correct key */
        if (prompt != MIB_PROMPT_UNSET) {
@@ -514,17 +541,15 @@
        }
        JsonNode *auth_params_node = json_node_new(JSON_NODE_OBJECT);
        json_node_set_object(auth_params_node, auth_params);
-       json_object_unref(auth_params);
 
        JsonObject *params_obj = json_object_new();
        /* if a re-auth is requested, clear the account */
        if (prompt & MIB_PROMPT_SELECT_ACCOUNT) {
                json_object_remove_member(auth_params, "account");
                json_object_remove_member(auth_params, "username");
-       } else {
-               json_object_set_object_member(params_obj, "account",
-                                                                         
json_object_ref(account));
        }
+       json_object_unref(auth_params);
+
        json_object_set_member(params_obj, "authParameters", auth_params_node);
        debug_print_json_object("mib_acquire_token_interactive_raw", "request",
                                                        params_obj);
@@ -568,6 +593,7 @@
        if (!account_json) {
                return NULL;
        }
+       MIBAccount *fallback_account = mib_account_from_json(account_json);
 
        JsonArray *scopes_array = mib_scopes_to_json(scopes);
        JsonObject *pop_params = auth_scheme ? 
mib_pop_params_to_json(auth_scheme) :
@@ -580,25 +606,24 @@
                                                                                
 claims_challenge, pop_params, NULL);
        }
        if (token_json) {
-               token = mib_prt_from_json(token_json);
-               if (!token)
-                       json_object_unref(token_json);
+               token = mib_prt_from_json(token_json, fallback_account);
+               json_object_unref(token_json);
        }
        if (!token) {
                token_json = mib_acquire_token_interactive_raw(
                        app, scopes_array, prompt, account_json, domain_hint,
                        claims_challenge, pop_params, NULL);
-               token = mib_prt_from_json(token_json);
+               if (token_json) {
+                       token = mib_prt_from_json(token_json, fallback_account);
+                       json_object_unref(token_json);
+               }
        }
        json_object_unref(account_json);
        json_array_unref(scopes_array);
        if (pop_params) {
                json_object_unref(pop_params);
        }
-       if (!token_json) {
-               return NULL;
-       }
-       json_object_unref(token_json);
+       g_clear_object(&fallback_account);
        return token;
 }
 
@@ -637,7 +662,8 @@
        gboolean ok;
 
        JsonObject *auth_params =
-               prepare_prt_auth_params(app, account, scopes, NULL, NULL, NULL, 
NULL);
+               prepare_prt_auth_params(app, account, scopes, NULL, NULL, NULL, 
NULL,
+                                                               sso_url, 
AT_PRT_SSO_COOKIE);
        JsonObject *params =
                prepare_prt_sso_request_data(account, auth_params, sso_url);
        debug_print_json_object("mib_acquire_prt_sso_cookie_raw", "request",
@@ -687,8 +713,8 @@
        return cookie;
 }
 
-static JsonObject *mib_generate_signed_http_request_raw(
-       MIBClientApp *app, const gchar *home_account_id, JsonObject *pop_params)
+static JsonObject *mib_generate_signed_http_request_raw(MIBClientApp *app,
+                                                                               
                                JsonObject *pop_params)
 {
        GError *error = NULL;
        gboolean ok;
@@ -696,7 +722,6 @@
        JsonObject *params = json_object_new();
        json_object_set_string_member(params, "clientId",
                                                                  
mib_client_app_get_client_id(app));
-       json_object_set_string_member(pop_params, "homeAccountId", 
home_account_id);
        json_object_ref(pop_params);
        json_object_set_object_member(params, "popParams", pop_params);
        debug_print_json_object("mib_generate_signed_http_request_raw", 
"request",
@@ -728,6 +753,7 @@
 {
        JsonObject *params_json;
        gchar *access_token = NULL;
+       const gchar *account_id = NULL;
 
        g_assert(app);
        g_assert(account);
@@ -737,8 +763,9 @@
        } else {
                params_json = json_object_new();
        }
-       JsonObject *token = mib_generate_signed_http_request_raw(
-               app, mib_account_get_home_account_id(account), params_json);
+       account_id = mib_account_get_home_account_id(account);
+       json_object_set_string_member(params_json, "homeAccountId", account_id);
+       JsonObject *token = mib_generate_signed_http_request_raw(app, 
params_json);
        json_object_unref(params_json);
        if (!token) {
                return NULL;
@@ -782,7 +809,8 @@
        JsonObject *resp_json = json_object_from_string(response);
        g_free(response);
        debug_print_json_object("mib_remove_account_raw", "response", 
resp_json);
-       json_object_unref(resp_json);
+       if (resp_json)
+               json_object_unref(resp_json);
        return 0;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/src/mib-pop-params.c 
new/sso-mib-0.8.0/src/mib-pop-params.c
--- old/sso-mib-0.7.0/src/mib-pop-params.c      2025-11-06 16:00:28.000000000 
+0100
+++ new/sso-mib-0.8.0/src/mib-pop-params.c      2026-03-17 10:52:48.000000000 
+0100
@@ -19,8 +19,7 @@
 
 static void mib_pop_params_finalize(GObject *gobject)
 {
-       MIBPopParams *priv =
-               mib_pop_params_get_instance_private(MIB_POP_PARAMS(gobject));
+       MIBPopParams *priv = MIB_POP_PARAMS(gobject);
        g_clear_pointer(&priv->resource_req_uri, g_free);
        g_clear_pointer(&priv->shr_claims, g_free);
        g_clear_pointer(&priv->shr_nonce, g_free);
@@ -95,6 +94,7 @@
 {
        g_assert(self);
        g_assert(claims);
+       g_free(self->shr_claims);
        self->shr_claims = g_strdup(claims);
 }
 
@@ -102,6 +102,7 @@
 {
        g_assert(self);
        g_assert(nonce);
+       g_free(self->shr_nonce);
        self->shr_nonce = g_strdup(nonce);
 }
 
@@ -109,5 +110,6 @@
 {
        g_assert(self);
        g_assert(kid);
+       g_free(self->kid);
        self->kid = g_strdup(kid);
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/src/mib-prt-impl.h 
new/sso-mib-0.8.0/src/mib-prt-impl.h
--- old/sso-mib-0.7.0/src/mib-prt-impl.h        2025-11-06 16:00:28.000000000 
+0100
+++ new/sso-mib-0.8.0/src/mib-prt-impl.h        2026-03-17 10:52:48.000000000 
+0100
@@ -7,6 +7,6 @@
 
 #include <json-glib/json-glib.h>
 #include "mib-prt.h"
+#include "mib-account.h"
 
-gchar *json_object_to_string(JsonObject *object);
-MIBPrt *mib_prt_from_json(JsonObject *token_json);
+MIBPrt *mib_prt_from_json(JsonObject *token_json, MIBAccount 
*fallback_account);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/src/mib-prt-sso-cookie.c 
new/sso-mib-0.8.0/src/mib-prt-sso-cookie.c
--- old/sso-mib-0.7.0/src/mib-prt-sso-cookie.c  2025-11-06 16:00:28.000000000 
+0100
+++ new/sso-mib-0.8.0/src/mib-prt-sso-cookie.c  2026-03-17 10:52:48.000000000 
+0100
@@ -19,8 +19,7 @@
 
 static void mib_prt_sso_cookie_finalize(GObject *gobject)
 {
-       MIBPrtSsoCookie *priv =
-               
mib_prt_sso_cookie_get_instance_private(MIB_PRT_SSO_COOKIE(gobject));
+       MIBPrtSsoCookie *priv = MIB_PRT_SSO_COOKIE(gobject);
        g_clear_pointer(&priv->name, g_free);
        g_clear_pointer(&priv->content, g_free);
        G_OBJECT_CLASS(mib_prt_sso_cookie_parent_class)->finalize(gobject);
@@ -39,6 +38,18 @@
 MIBPrtSsoCookie *mib_prt_sso_cookie_from_json(JsonObject *cookie_json)
 {
        MIBPrtSsoCookie *cookie;
+       /* microsoft-identity-broker > 2.0.1 */
+       if (json_object_has_member(cookie_json, "cookieItems")) {
+               JsonArray *cookie_items =
+                       json_object_get_array_member(cookie_json, 
"cookieItems");
+               if (!cookie_items || !json_array_get_length(cookie_items)) {
+                       return NULL;
+               }
+               JsonObject *cookie_json_inner =
+                       json_array_get_object_element(cookie_items, 0);
+               return mib_prt_sso_cookie_from_json(cookie_json_inner);
+       }
+
        if (!json_object_has_member(cookie_json, "cookieName") ||
                !json_object_has_member(cookie_json, "cookieContent")) {
                g_warning("invalid cookie data");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/src/mib-prt.c 
new/sso-mib-0.8.0/src/mib-prt.c
--- old/sso-mib-0.7.0/src/mib-prt.c     2025-11-06 16:00:28.000000000 +0100
+++ new/sso-mib-0.8.0/src/mib-prt.c     2026-03-17 10:52:48.000000000 +0100
@@ -24,7 +24,7 @@
 
 static void mib_prt_finalize(GObject *gobject)
 {
-       MIBPrt *self = mib_prt_get_instance_private(MIB_PRT(gobject));
+       MIBPrt *self = MIB_PRT(gobject);
        g_clear_pointer(&self->access_token, g_free);
        g_clear_object(&self->account);
        g_clear_pointer(&self->client_info, g_free);
@@ -57,12 +57,11 @@
        return MIB_AUTH_SCHEME_BEARER;
 }
 
-MIBPrt *mib_prt_from_json(JsonObject *token_json)
+MIBPrt *mib_prt_from_json(JsonObject *token_json, MIBAccount *fallback_account)
 {
        MIBAccount *account = NULL;
-       JsonObject *account_json = NULL;
        MIBPrt *token = NULL;
-       const char *members[] = { "accessToken",  "accessTokenType", "account",
+       const char *members[] = { "accessToken",  "accessTokenType",
                                                          "clientInfo",   
"expiresOn",           "idToken",
                                                          "grantedScopes" };
 
@@ -82,8 +81,12 @@
                g_strdup(json_object_get_string_member(broker_resp, 
"accessToken"));
        token->access_token_type = mib_prt_token_type_from_ext(
                json_object_get_int_member(broker_resp, "accessTokenType"));
-       account_json = json_object_get_object_member(broker_resp, "account");
-       account = mib_account_from_json(account_json);
+       if (json_object_has_member(broker_resp, "account")) {
+               JsonObject *account_json = 
json_object_get_object_member(broker_resp, "account");
+               account = mib_account_from_json(account_json);
+       }
+       if (!account && fallback_account)
+               account = g_object_ref(fallback_account);
        if (!account) {
                g_warning("account data is not valid");
                g_object_unref(token);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/src/mib-utils.c 
new/sso-mib-0.8.0/src/mib-utils.c
--- old/sso-mib-0.7.0/src/mib-utils.c   2025-11-06 16:00:28.000000000 +0100
+++ new/sso-mib-0.8.0/src/mib-utils.c   2026-03-17 10:52:48.000000000 +0100
@@ -31,9 +31,14 @@
        g_object_unref(gen);
 }
 
-void debug_print_json_object(gchar *func, gchar *scope, JsonObject *object)
+void debug_print_json_object(const gchar *func, const gchar *scope,
+                                                        JsonObject *object)
 {
        g_debug("json-object from %s,%s", func, scope);
+       if (!object) {
+               g_debug("(null)");
+               return;
+       }
        print_json_object(object);
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/src/mib-utils.h 
new/sso-mib-0.8.0/src/mib-utils.h
--- old/sso-mib-0.7.0/src/mib-utils.h   2025-11-06 16:00:28.000000000 +0100
+++ new/sso-mib-0.8.0/src/mib-utils.h   2026-03-17 10:52:48.000000000 +0100
@@ -16,5 +16,6 @@
 
 gchar *json_object_to_string(JsonObject *object);
 JsonObject *json_object_from_string(const gchar *data);
-void debug_print_json_object(gchar *func, gchar *scope, JsonObject *object);
+void debug_print_json_object(const gchar *func, const gchar *scope,
+                                                        JsonObject *object);
 JsonArray *mib_scopes_to_json(GSList *scopes);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sso-mib-0.7.0/src/sso-mib-tool.c 
new/sso-mib-0.8.0/src/sso-mib-tool.c
--- old/sso-mib-0.7.0/src/sso-mib-tool.c        2025-11-06 16:00:28.000000000 
+0100
+++ new/sso-mib-0.8.0/src/sso-mib-tool.c        2026-03-17 10:52:48.000000000 
+0100
@@ -4,11 +4,13 @@
  */
 
 #include <libgen.h>
-#include <stdio.h>
 #include <signal.h>
 #include <sys/time.h>
+#include <unistd.h>
 #include <json-glib/json-glib.h>
+#ifdef WITH_LIBJWT
 #include <jwt.h>
+#endif
 
 #include "sso-mib.h"
 
@@ -17,36 +19,143 @@
 // Fake MSAL CPP version
 #define MSAL_CPP_VERSION "1.28.0"
 
+#define FORMAT_JSON "json"
+#define FORMAT_TEXT "text"
+
 static GCancellable *cancellable = NULL;
 
 static void sig_handler(int signo)
 {
        if (signo == SIGINT) {
                if (cancellable) {
-                       g_print("Interrupted. Cancel in-flight operations.\n");
+                       const char msg[] = "Interrupted. Cancel in-flight 
operations.\n";
+                       // use a dummy conditional to denote we don't care 
about the result
+                       if (write(STDERR_FILENO, msg, sizeof(msg) - 1)) {
+                       }
                        g_cancellable_cancel(cancellable);
                }
        }
 }
 
-static void print_decoded_jwt(const gchar *token)
+#ifdef WITH_LIBJWT
+#if LIBJWT_VERSION_MAJOR == 1 || LIBJWT_VERSION_MAJOR == 2
+static int decode_headers_and_claims(const gchar *token, char **grants,
+                                                                        char 
**hdrs)
 {
        jwt_t *jwt = NULL;
-       int ret = 0;
+       int ret = jwt_decode(&jwt, token, NULL, 0);
+       if (ret != 0)
+               return ret;
+       *hdrs = jwt_get_headers_json(jwt, NULL);
+       *grants = jwt_get_grants_json(jwt, NULL);
+       jwt_free(jwt);
+       return 0;
+}
+#else
+struct jwt_cb_ctx {
+       char **grants;
+       char **hdrs;
+};
+
+static int on_check_cb(jwt_t *jwt, jwt_config_t *config)
+{
+       jwt_value_t header_val;
+       jwt_value_t claims_val;
+       struct jwt_cb_ctx *ctx = config->ctx;
+
+       jwt_set_GET_JSON(&header_val, NULL);
+       if (jwt_header_get(jwt, &header_val) == JWT_VALUE_ERR_NONE) {
+               *ctx->hdrs = header_val.json_val;
+       }
+       jwt_set_GET_JSON(&claims_val, NULL);
+       if (jwt_claim_get(jwt, &claims_val) == JWT_VALUE_ERR_NONE)
+               *ctx->grants = claims_val.json_val;
+       return 0;
+}
+
+static int decode_headers_and_claims(const gchar *token, char **grants,
+                                                                        char 
**hdrs)
+{
+       struct jwt_cb_ctx ctx = { .grants = grants, .hdrs = hdrs };
+       jwt_checker_t *checker = jwt_checker_new();
+       jwt_checker_setcb(checker, on_check_cb, &ctx);
+       jwt_checker_verify(checker, token);
+       jwt_checker_free(checker);
+       return 0;
+}
+#endif
+
+static void print_decoded_jwt(const gchar *token)
+{
        char *grants = NULL;
        char *hdrs = NULL;
-       ret = jwt_decode(&jwt, token, NULL, 0);
-       if (ret != 0) {
+       if (decode_headers_and_claims(token, &grants, &hdrs) != 0) {
                g_print("Error: Failed to decode JWT\n");
                return;
        }
-       hdrs = jwt_get_headers_json(jwt, NULL);
-       grants = jwt_get_grants_json(jwt, NULL);
        g_print("%s\n", hdrs);
        g_print("%s\n", grants);
        free(hdrs);
        free(grants);
-       jwt_free(jwt);
+}
+#else
+static void print_decoded_jwt(const gchar *token)
+{
+       g_printerr("token decoding requires libjwt (dependency missing)\n");
+}
+#endif
+
+static void print_json_builder(JsonBuilder *builder)
+{
+       JsonGenerator *generator = json_generator_new();
+       JsonNode *root = json_builder_get_root(builder);
+       json_generator_set_root(generator, root);
+
+       gchar *buf = json_generator_to_data(generator, NULL);
+       g_print("%s\n", buf);
+       g_free(buf);
+
+       json_node_free(root);
+       g_object_unref(generator);
+}
+
+static void json_builder_add_jwt_token(JsonBuilder *builder, const gchar 
*token)
+{
+       char *grants = NULL;
+       char *hdrs = NULL;
+       if (decode_headers_and_claims(token, &grants, &hdrs) != 0) {
+               g_print("Error: Failed to decode JWT\n");
+               return;
+       }
+
+       json_builder_begin_object(builder);
+
+       GError *error = NULL;
+       JsonParser *parser = json_parser_new();
+       if (json_parser_load_from_data(parser, hdrs, -1, &error)) {
+               JsonNode *node = json_parser_get_root(parser);
+               json_builder_set_member_name(builder, "headers");
+               JsonNode *copied = json_node_copy(node);
+               json_builder_add_value(builder, copied);
+       } else {
+               g_printerr("Error parsing JSON string: %s\n", error->message);
+       }
+       g_clear_error(&error);
+
+       if (json_parser_load_from_data(parser, grants, -1, &error)) {
+               JsonNode *node = json_parser_get_root(parser);
+               json_builder_set_member_name(builder, "grants");
+               JsonNode *copied = json_node_copy(node);
+               json_builder_add_value(builder, copied);
+       } else {
+               g_printerr("Error parsing JSON string: %s\n", error->message);
+       }
+       g_clear_error(&error);
+
+       g_object_unref(parser);
+       free(hdrs);
+       free(grants);
+       json_builder_end_object(builder);
 }
 
 static void print_prt_sso_cookie(MIBPrtSsoCookie *cookie, int decode)
@@ -63,6 +172,27 @@
        }
 }
 
+static void json_print_prt_sso_cookie(MIBPrtSsoCookie *cookie, int decode)
+{
+       JsonBuilder *builder = json_builder_new();
+       json_builder_begin_object(builder);
+
+       json_builder_set_member_name(builder, "cookie_name");
+       json_builder_add_string_value(builder, 
mib_prt_sso_cookie_get_name(cookie));
+
+       json_builder_set_member_name(builder, "cookie_content");
+       const gchar *content = mib_prt_sso_cookie_get_content(cookie);
+       if (decode) {
+               json_builder_add_jwt_token(builder, content);
+       } else {
+               json_builder_add_string_value(builder, content);
+       }
+
+       json_builder_end_object(builder);
+       print_json_builder(builder);
+       g_object_unref(builder);
+}
+
 static void print_account(MIBAccount *account, gchar *prefix)
 {
        char realm_str[37];
@@ -87,6 +217,90 @@
        g_print("%susername: %s\n", prefix, mib_account_get_username(account));
 }
 
+static void print_account_list(GSList *accounts, gchar *prefix)
+{
+       int i = 0;
+       for (GSList *iter = accounts; iter; iter = g_slist_next(iter)) {
+               g_print("# Account %d\n", i++);
+               MIBAccount *account = (MIBAccount *)iter->data;
+               print_account(account, "  ");
+       }
+}
+
+static void json_builder_add_account(JsonBuilder *builder, MIBAccount *account)
+{
+       char realm_str[37];
+       uuid_t realm;
+       mib_account_get_realm(account, realm);
+       uuid_unparse(realm, realm_str);
+
+       if (mib_account_get_client_info(account)) {
+               json_builder_set_member_name(builder, "client_info");
+               json_builder_add_string_value(builder,
+                                                                         
mib_account_get_client_info(account));
+       }
+
+       json_builder_set_member_name(builder, "environment");
+       json_builder_add_string_value(builder,
+                                                                 
mib_account_get_environment(account));
+
+       if (mib_account_get_family_name(account)) {
+               json_builder_set_member_name(builder, "family_name");
+               json_builder_add_string_value(builder,
+                                                                         
mib_account_get_family_name(account));
+       }
+
+       json_builder_set_member_name(builder, "given_name");
+       json_builder_add_string_value(builder, 
mib_account_get_given_name(account));
+
+       json_builder_set_member_name(builder, "home_account_id");
+       json_builder_add_string_value(builder,
+                                                                 
mib_account_get_home_account_id(account));
+
+       json_builder_set_member_name(builder, "local_account_id");
+       json_builder_add_string_value(builder,
+                                                                 
mib_account_get_local_account_id(account));
+
+       json_builder_set_member_name(builder, "name");
+       json_builder_add_string_value(builder, mib_account_get_name(account));
+
+       json_builder_set_member_name(builder, "password_expiry");
+       json_builder_add_int_value(builder,
+                                                          
mib_account_get_password_expiry(account));
+
+       json_builder_set_member_name(builder, "realm");
+       json_builder_add_string_value(builder, realm_str);
+
+       json_builder_set_member_name(builder, "username");
+       json_builder_add_string_value(builder, 
mib_account_get_username(account));
+}
+
+static void json_print_account(MIBAccount *account)
+{
+       JsonBuilder *builder = json_builder_new();
+       json_builder_begin_object(builder);
+       json_builder_add_account(builder, account);
+       json_builder_end_object(builder);
+       print_json_builder(builder);
+       g_object_unref(builder);
+}
+
+static void json_print_account_list(GSList *accounts)
+{
+       JsonBuilder *builder = json_builder_new();
+       json_builder_begin_array(builder);
+
+       for (GSList *iter = accounts; iter; iter = g_slist_next(iter)) {
+               json_builder_begin_object(builder);
+               json_builder_add_account(builder, (MIBAccount *)iter->data);
+               json_builder_end_object(builder);
+       }
+
+       json_builder_end_array(builder);
+       print_json_builder(builder);
+       g_object_unref(builder);
+}
+
 static const char *auth_scheme_to_str(enum MIB_AUTH_SCHEME scheme)
 {
        if (scheme == MIB_AUTH_SCHEME_POP) {
@@ -99,7 +313,7 @@
 static void print_prt_token(MIBPrt *token, int decode)
 {
        char buffer[32];
-       struct tm *tm_info;
+       struct tm tm_info;
        struct timeval tv;
        const char *token_type =
                auth_scheme_to_str(mib_prt_get_access_token_type(token));
@@ -123,13 +337,65 @@
        }
        g_print("\n");
        tv.tv_sec = mib_prt_get_expires_on(token);
-       tm_info = localtime(&tv.tv_sec);
-       strftime(buffer, 32, "%Y-%m-%d %H:%M:%S", tm_info);
+       localtime_r(&tv.tv_sec, &tm_info);
+       strftime(buffer, sizeof(buffer) - 1, "%Y-%m-%d %H:%M:%S", &tm_info);
        g_print("%sexpires-on: %s\n", p, buffer);
        g_print("%saccount:\n", p);
        print_account(mib_prt_get_account(token), "# ");
 }
 
+static void json_print_prt_token(MIBPrt *token, int decode)
+{
+       JsonBuilder *builder = json_builder_new();
+       json_builder_begin_object(builder);
+       if (decode) {
+               json_builder_set_member_name(builder, "access_token");
+               json_builder_add_jwt_token(builder, 
mib_prt_get_access_token(token));
+               json_builder_set_member_name(builder, "id_token");
+               json_builder_add_jwt_token(builder, 
mib_prt_get_id_token(token));
+       } else {
+               json_builder_set_member_name(builder, "access_token");
+               json_builder_add_string_value(builder, 
mib_prt_get_access_token(token));
+               json_builder_set_member_name(builder, "id_token");
+               json_builder_add_string_value(builder, 
mib_prt_get_id_token(token));
+       }
+
+       json_builder_set_member_name(builder, "access_token_type");
+       json_builder_add_string_value(
+               builder, 
auth_scheme_to_str(mib_prt_get_access_token_type(token)));
+
+       json_builder_set_member_name(builder, "client_info");
+       json_builder_add_string_value(builder, mib_prt_get_client_info(token));
+
+       json_builder_set_member_name(builder, "granted_scopes");
+       gchar *const *scopes = mib_prt_get_granted_scopes(token);
+       json_builder_begin_array(builder);
+       for (int i = 0; scopes[i]; i++) {
+               json_builder_add_string_value(builder, scopes[i]);
+       }
+       json_builder_end_array(builder);
+
+       struct timeval tv;
+       tv.tv_sec = mib_prt_get_expires_on(token);
+       struct tm tm_info;
+       localtime_r(&tv.tv_sec, &tm_info);
+       char buffer[32];
+       strftime(buffer, sizeof(buffer) - 1, "%Y-%m-%d %H:%M:%S", &tm_info);
+       json_builder_set_member_name(builder, "expires_on");
+       json_builder_add_string_value(builder, buffer);
+
+       json_builder_set_member_name(builder, "account");
+       json_builder_begin_object(builder);
+       json_builder_add_account(builder, mib_prt_get_account(token));
+       json_builder_end_object(builder);
+
+       // finish builder
+       json_builder_end_object(builder);
+
+       print_json_builder(builder);
+       g_object_unref(builder);
+}
+
 static JsonObject *parse_to_json_object(const gchar *data)
 {
        JsonParser *parser = json_parser_new();
@@ -185,7 +451,7 @@
                json_object_get_string_member(params_json, 
"resourceRequestUri");
        params = mib_pop_params_new(auth_scheme, req_method, req_uri);
        if (!params) {
-               return NULL;
+               goto err;
        }
        if (json_object_has_member(params_json, "shrClaims")) {
                mib_pop_params_set_shr_claims(
@@ -193,15 +459,23 @@
        }
        if (json_object_has_member(params_json, "shrNonce")) {
                mib_pop_params_set_shr_nonce(
-                       params,
-                       g_strdup(json_object_get_string_member(params_json, 
"shrNonce")));
+                       params, json_object_get_string_member(params_json, 
"shrNonce"));
        }
        return params;
 err:
-       g_object_unref(params);
+       if (params)
+               g_object_unref(params);
        return NULL;
 }
 
+GSList *default_scope_if_empty(GSList *scopes)
+{
+       if (!scopes) {
+               scopes = g_slist_append(scopes, 
g_strdup(MIB_SCOPE_GRAPH_DEFAULT));
+       }
+       return scopes;
+}
+
 static void print_help(char *name)
 {
        g_print("Usage: %s COMMAND [OPTION]...\n", basename(name));
@@ -213,26 +487,36 @@
        g_print("  -a <account>  Account index (default: 0)\n");
        g_print("  -A <upn>      Select account by User Principal Name\n");
        g_print("  -d            Decode JWT\n");
+       g_print("  -f <format>   Set output format: %s, %s (default: %s)\n",
+                       FORMAT_TEXT, FORMAT_JSON, FORMAT_TEXT);
        g_print("  -h            Print this help message\n");
        g_print("  -I            Enforce interactive token acquire\n");
        g_print("  -P            Proof-of-Possession parameters\n");
+       g_print("  -r <uri>      OIDC redirect URI\n");
        g_print("  -s <client_id> Azure client application ID (default: %s)\n",
                        CLIENT_ID_DEFAULT);
+       g_print("  -S <scope>    OIDC scope (repeatable)\n");
        g_print("  -t <token>    Renew token\n");
+       g_print("  -x <authority> Entra ID authority (default: %s)\n",
+                       MIB_AUTHORITY_COMMON);
 }
 
 int main(int argc, char **argv)
 {
        int account_idx = 0;
        char *account_hint = NULL;
+       const gchar *authority = MIB_AUTHORITY_COMMON;
        char *command = NULL;
        gchar *client_id = CLIENT_ID_DEFAULT;
        gchar *pop_params = NULL;
        JsonObject *pop_params_json = NULL;
        MIBPopParams *auth_params = NULL;
+       gchar *redirect_uri = NULL;
+       GSList *scopes = NULL;
        char *renew_token = NULL;
        int decode = 0;
        int enforce_interactive = 0;
+       gchar *format = FORMAT_TEXT;
        int c;
        if (argc < 2) {
                print_help(argv[0]);
@@ -243,7 +527,7 @@
                print_help(argv[0]);
                return 0;
        }
-       while ((c = getopt(argc - 1, argv + 1, "a:A:dhIP:s:t:")) != -1)
+       while ((c = getopt(argc - 1, argv + 1, "a:A:df:hIP:r:s:S:t:x:")) != -1)
                switch (c) {
                case 'a':
                        account_idx = atoi(optarg);
@@ -255,6 +539,9 @@
                case 'd':
                        decode = 1;
                        break;
+               case 'f':
+                       format = optarg;
+                       break;
                case 'h':
                        print_help(argv[0]);
                        return 0;
@@ -264,12 +551,22 @@
                case 'P':
                        pop_params = optarg;
                        break;
+               case 'r':
+                       g_clear_pointer(&redirect_uri, g_free);
+                       redirect_uri = g_strdup(optarg);
+                       break;
                case 's':
                        client_id = optarg;
                        break;
+               case 'S':
+                       scopes = g_slist_append(scopes, g_strdup(optarg));
+                       break;
                case 't':
                        renew_token = optarg;
                        break;
+               case 'x':
+                       authority = optarg;
+                       break;
                case '?':
                        print_help(argv[0]);
                        return 1;
@@ -280,8 +577,12 @@
                g_print("Error: -c <command> is required\n");
                return 1;
        }
+       if (scopes && (strncmp(command, "acquire", strlen("acquire")) != 0)) {
+               g_slist_free_full(scopes, g_free);
+               g_printerr(
+                       "Warning: scopes must only be provided on acquire* 
commands. Ignoring\n");
+       }
 
-       const gchar *authority = MIB_AUTHORITY_COMMON;
        cancellable = g_cancellable_new();
        MIBClientApp *app =
                mib_public_client_app_new(client_id, authority, cancellable, 
NULL);
@@ -290,6 +591,10 @@
                return 1;
        }
        mib_client_app_set_enforce_interactive(app, enforce_interactive);
+       if (redirect_uri) {
+               mib_client_app_set_redirect_uri(app, redirect_uri);
+               g_clear_pointer(&redirect_uri, g_free);
+       }
 
        // register cancellation handler
        signal(SIGINT, sig_handler);
@@ -316,7 +621,14 @@
                        g_object_unref(cancellable);
                        return 1;
                }
-               print_account(account, "  ");
+               if (g_ascii_strcasecmp(format, FORMAT_TEXT) == 0) {
+                       print_account(account, "  ");
+               } else if (g_ascii_strcasecmp(format, FORMAT_JSON) == 0) {
+                       json_print_account(account);
+               } else {
+                       g_print("Error[getAccounts]: Unsupported output format: 
%s\n",
+                                       format);
+               }
                g_object_unref(account);
        } else if (strcmp(command, "getAccounts") == 0) {
                GSList *accounts = mib_client_app_get_accounts(app);
@@ -326,10 +638,13 @@
                        g_object_unref(cancellable);
                        return 1;
                }
-               for (GSList *iter = accounts; iter; iter = g_slist_next(iter)) {
-                       g_print("# Account %d\n", account_idx++);
-                       MIBAccount *account = (MIBAccount *)iter->data;
-                       print_account(account, "  ");
+               if (g_ascii_strcasecmp(format, FORMAT_TEXT) == 0) {
+                       print_account_list(accounts, " ");
+               } else if (g_ascii_strcasecmp(format, FORMAT_JSON) == 0) {
+                       json_print_account_list(accounts);
+               } else {
+                       g_print("Error[getAccounts]: Unsupported output format: 
%s\n",
+                                       format);
                }
                g_slist_free_full(accounts, (GDestroyNotify)g_object_unref);
        } else if (strcmp(command, "removeAccount") == 0) {
@@ -353,8 +668,7 @@
                        return 1;
                }
        } else if (strcmp(command, "acquirePrtSsoCookie") == 0) {
-               GSList *scopes = NULL;
-               scopes = g_slist_append(scopes, 
g_strdup(MIB_SCOPE_GRAPH_DEFAULT));
+               scopes = default_scope_if_empty(scopes);
                GSList *accounts = mib_client_app_get_accounts(app);
                if (!accounts) {
                        g_print("Error[acquirePrtSsoCookie]: No accounts 
found\n");
@@ -375,11 +689,18 @@
                        g_object_unref(cancellable);
                        return 1;
                }
-               print_prt_sso_cookie(prt_cookie, decode);
+               if (g_ascii_strcasecmp(format, FORMAT_TEXT) == 0) {
+                       print_prt_sso_cookie(prt_cookie, decode);
+               } else if (g_ascii_strcasecmp(format, FORMAT_JSON) == 0) {
+                       json_print_prt_sso_cookie(prt_cookie, decode);
+               } else {
+                       g_print(
+                               "Error[acquirePrtSsoCookie]: Unsupported output 
format: %s\n",
+                               format);
+               }
                g_object_unref(prt_cookie);
        } else if (strcmp(command, "acquireTokenSilent") == 0) {
-               GSList *scopes = NULL;
-               scopes = g_slist_append(scopes, 
g_strdup(MIB_SCOPE_GRAPH_DEFAULT));
+               scopes = default_scope_if_empty(scopes);
                GSList *accounts = mib_client_app_get_accounts(app);
                if (!accounts) {
                        g_print("Error[acquireTokenSilent]: No accounts 
found\n");
@@ -401,11 +722,18 @@
                        g_object_unref(cancellable);
                        return 1;
                }
-               print_prt_token(prt_token, decode);
+               if (g_ascii_strcasecmp(format, FORMAT_TEXT) == 0) {
+                       print_prt_token(prt_token, decode);
+               } else if (g_ascii_strcasecmp(format, FORMAT_JSON) == 0) {
+                       json_print_prt_token(prt_token, decode);
+               } else {
+                       g_print(
+                               "Error[acquireTokenSilent]: Unsupported output 
format: %s\n",
+                               format);
+               }
                g_object_unref(prt_token);
        } else if (strcmp(command, "acquireTokenInteractive") == 0) {
-               GSList *scopes = NULL;
-               scopes = g_slist_append(scopes, 
g_strdup(MIB_SCOPE_GRAPH_DEFAULT));
+               scopes = default_scope_if_empty(scopes);
                MIBPrt *prt_token = mib_client_app_acquire_token_interactive(
                        app, scopes, MIB_PROMPT_CONSENT, NULL, NULL, NULL, 
auth_params);
                g_slist_free_full(scopes, g_free);
@@ -418,7 +746,15 @@
                        g_object_unref(cancellable);
                        return 1;
                }
-               print_prt_token(prt_token, decode);
+               if (g_ascii_strcasecmp(format, FORMAT_TEXT) == 0) {
+                       print_prt_token(prt_token, decode);
+               } else if (g_ascii_strcasecmp(format, FORMAT_JSON) == 0) {
+                       json_print_prt_token(prt_token, decode);
+               } else {
+                       g_print(
+                               "Error[acquireTokenInteractive]: Unsupported 
output format: %s\n",
+                               format);
+               }
                g_object_unref(prt_token);
        } else if (strcmp(command, "getLinuxBrokerVersion") == 0) {
                gchar *version =
@@ -456,10 +792,28 @@
                g_object_unref(auth_params);
                g_slist_free_full(accounts, (GDestroyNotify)g_object_unref);
                if (token) {
-                       if (decode) {
-                               print_decoded_jwt(token);
+                       if (g_ascii_strcasecmp(format, FORMAT_TEXT) == 0) {
+                               if (decode) {
+                                       print_decoded_jwt(token);
+                               } else {
+                                       g_print("HTTP request token: %s\n", 
token);
+                               }
+                       } else if (g_ascii_strcasecmp(format, FORMAT_JSON) == 
0) {
+                               JsonBuilder *builder = json_builder_new();
+                               json_builder_begin_object(builder);
+                               json_builder_set_member_name(builder, "token");
+                               if (decode) {
+                                       json_builder_add_jwt_token(builder, 
token);
+                               } else {
+                                       json_builder_add_string_value(builder, 
token);
+                               }
+                               json_builder_end_object(builder);
+                               print_json_builder(builder);
+                               g_object_unref(builder);
                        } else {
-                               g_print("HTTP request token: %s\n", token);
+                               g_print(
+                                       "Error[generateSignedHttpRequest]: 
Unsupported output format: %s\n",
+                                       format);
                        }
                        g_free(token);
                } else {

Reply via email to