Skip to main content
GNOME application web API integration diagram showing libsoup, GLib async I/O, and GNOME Online Accounts OAuth flow

GNOME Apps and Web APIs: Integration Notes

GNOME applications that communicate with web APIs do so through a reasonably consistent set of libraries: libsoup for HTTP, GLib and GIO for async I/O and cancellation, and GNOME Online Accounts for delegating OAuth credential management. The pattern is well-established across the GNOME application ecosystem — GNOME Calendar, GNOME Photos, GNOME Files's network backends, Evolution, and third-party GTK applications all use variations of the same stack. This page documents how these components fit together, the libsoup API as it changed between versions 2.x and 3.x, how GNOME Online Accounts exposes credentials to applications via D-Bus, and the practical debugging approaches when network access in a GTK application behaves unexpectedly. This is part of the technote section. Related context: GNOME web app icon handling covers the web-facing side, and GNOME CalDAV configuration covers the CalDAV-specific application of this stack.


The GNOME web access stack

→ Short Answer

The standard GNOME web access stack has three layers. libsoup handles HTTP sessions, TLS, cookies, authentication, and request/response management. GLib/GIO provides the GMainLoop event loop, GCancellable for async cancellation, GTask for async operation wrappers, and GError for structured error propagation. GNOME Online Accounts (GOA) handles OAuth flows and credential storage, exposing account tokens to applications via D-Bus so that individual apps never directly handle OAuth client secrets or user passwords.

The separation of concerns is deliberate. Applications that use GOA for credential management don't implement OAuth flows themselves — they request credentials from the goa-daemon process via D-Bus and receive access tokens. This centralises token refresh logic, reduces the surface for token handling bugs, and means users authenticate to services once rather than per-application.


libsoup: versions and API changes

libsoup went through a significant API revision between the 2.x series and 3.x. The 3.x API removed the synchronous request methods that were a common source of blocking-in-the-main-thread bugs, made async operation the only supported pattern, and aligned the API more closely with GIO conventions.

↻ What Changed

libsoup 2.x provided both synchronous (soup_session_send_message) and asynchronous methods. Many GTK application tutorials and older code used the synchronous API for simplicity, which blocked the GTK main loop during network requests and produced unresponsive UIs. libsoup 3.x removed all synchronous request methods, forcing all HTTP access through async patterns using SoupSession with callbacks or GTask. Applications migrating from libsoup 2.x to 3.x must refactor any synchronous network code.

A basic async GET request in libsoup 3.x:

libsoup 3.x — async HTTP GET with GTask
SoupSession *session = soup_session_new();
SoupMessage *msg = soup_message_new(SOUP_METHOD_GET,
"https://api.example.com/v1/data");
soup_session_send_async(session, msg, G_PRIORITY_DEFAULT,
cancellable, on_response_received,
user_data);
// In on_response_received callback:
// GInputStream *stream = soup_session_send_finish(session, res, &error);
⚙ Compatibility Note

Distributions shipped libsoup 2.x and 3.x in parallel for several release cycles to support applications that had not yet migrated. The library names are distinct (libsoup-2.4 vs libsoup-3.0), so they don't conflict at the package level. However, a GTK application that links against libsoup 2.x on a system where the GNOME shell and its dependencies use libsoup 3.x runs both library versions simultaneously — not a problem in practice but worth knowing when debugging memory or TLS issues.


GNOME Online Accounts credential access

For applications that authenticate to third-party services, GOA provides a D-Bus API that returns access tokens without the application needing to know the OAuth client secret, handle PKCE, or manage token refresh.

Querying GOA accounts via D-Bus (command-line inspection)
# List configured online accounts and their service providers:
gdbus call --session \
--dest org.gnome.OnlineAccounts \
--object-path /org/gnome/OnlineAccounts \
--method org.freedesktop.DBus.ObjectManager.GetManagedObjects \
| python3 -m json.tool | grep -A 2 '"ProviderName"'

In application code, GoaClient provides the account list and GoaOAuth2Based provides access token retrieval. The application calls goa_oauth2_based_call_get_access_token_sync (or the async variant), receives a short-lived token, and uses it in HTTP Authorization headers. GOA handles token refresh transparently.

⬡ Observed Behaviour

The GOA credential delegation works correctly for services like Google, Nextcloud, and Microsoft that use standard OAuth 2.0 flows. It does not work well for services with non-standard authentication or services that GOA does not have a configured provider for. For custom or private services, applications fall back to libsecret for credential storage and implement their own authentication logic — GOA is not a universal credential manager, it's a collection of per-provider authentication modules.


Debugging GNOME app network access

When a GNOME application fails to connect to a web API and the error message is unhelpful, the debugging path involves libsoup's debug logging and D-Bus inspection.

Enable libsoup debug logging for a GNOME app
# Set SOUP_DEBUG to log HTTP request/response details:
SOUP_DEBUG=all gnome-calendar 2>&1 | grep -E 'soup|http|request|response'

# Or use G_MESSAGES_DEBUG for GLib-level messages:
G_MESSAGES_DEBUG=all gnome-calendar 2>&1 | grep -i 'caldav\|http\|goa'
⚠ Common Pitfall

A frequent debugging dead end is assuming that network access failures in GNOME apps are TLS certificate problems. They often are not. The more common cause is GOA token expiry combined with a failed refresh — the app has a cached but expired token, GOA fails to refresh it silently, and the API returns 401. The application may surface this as a generic "couldn't connect" error. Checking GOA account status in Settings → Online Accounts and removing and re-adding the account resolves this in most cases.


Practical patterns

Applications that implement their own HTTP access outside GOA typically use SoupSession with a SoupCookieJar for session management, SoupLogger during development, and GCancellable instances tied to the application window or operation lifetime. Request queuing and rate limiting must be implemented in the application layer — libsoup does not queue or throttle requests automatically.

The GOA pattern is preferable for any service where GOA has a provider: it reduces implementation surface, keeps token handling out of application code, and means users see a consistent authentication experience across GNOME applications accessing the same service.