Linux and macOS
The library and the demo run on macOS and on Linux desktops (GNOME, KDE). Both versions do the same protocol work with the same checks. They differ in what each platform provides:
- how the browser returns to the app;
- where tokens and the DPoP key are kept;
- how TLS trust is configured;
- what the user interface is built with.
This page lists every difference, for the library and for the demo app.
At a glance
| macOS | Linux (GNOME, KDE) | |
|---|---|---|
| Sign-in window | SystemWebAuthenticator: ASWebAuthenticationSession, a sheet over the app using the default browser’s session |
LoopbackWebAuthenticator: the default browser, opened with xdg-open, in its own window or tab |
| Redirect URI | Private-use scheme: net.rcbj.caepdemo:/callback (RFC 8252 §7.1) |
Loopback: http://127.0.0.1:53682/callback (RFC 8252 §7.3) |
| Post-logout redirect URI | net.rcbj.caepdemo:/logged-out |
http://127.0.0.1:53682/logged-out |
| Token cache | Keychain (KeychainTokenStore): encrypted at rest, kept across launches |
Memory (MemoryTokenStore): cleared when the app quits |
| DPoP key | Secure Enclave (SecureEnclaveKeyStore, non-extractable) when the Mac has one, else Keychain (KeychainKeyStore) |
Memory (MemoryKeyStore): a new key every launch |
| After a restart | Every account is still signed in | Accounts must sign in again |
| HTTP | URLSession |
URLSession. With TrustedCertificates or InsecureSkipTLSVerification set, the system’s curl |
| Demo’s TLS default | Certificates verified | Verification off (InsecureSkipTLSVerification), for the local iya-sts |
Extra trusted CAs (TrustedCertificates) |
Added as anchors to the URLSession trust evaluation | Written to a private CA bundle passed to curl --cacert |
| Demo user interface | SwiftUI | GTK 4, through SwiftCrossUI 0.9.0 |
| Demo configuration file | OIDCConfiguration.plist |
OIDCConfiguration-Linux.plist, or ~/.config/caep-demo/OIDCConfiguration.plist |
| Demo package | Demo/scripts/build-app.sh → CAEPDemo.app (ad-hoc signed) |
install/appimage.sh → CAEP_Demo-<version>-x86_64.AppImage |
| Minimum OS | macOS 13 for the library; macOS 14 for the demo | glibc 2.35 and GTK 4.6 (Ubuntu 22.04 or newer) |
Everything else is the same code on both platforms:
- discovery and metadata validation;
- PKCE,
stateandnonce; - PAR and DPoP proofs;
- RFC 9207 issuer checks;
- ID token validation;
- refresh and revocation;
- several accounts with one active account;
- the SSF receiver and every CAEP handler;
- the demo’s event policies.
The library’s tests run on Linux and on macOS in CI.
Signing in
macOS. ASWebAuthenticationSession opens the provider’s page in a sheet tied to the app’s window. It uses the default browser’s cookies, so single sign-on and several accounts work. The session ends when the browser is sent to the private-use scheme, which macOS hands back to the app; no app registration is needed. Closing the sheet throws an error whose isUserCancellation is true.
Linux. There is no ASWebAuthenticationSession. LoopbackWebAuthenticator does what RFC 8252 §7.3 describes:
- It starts listening on
127.0.0.1at the redirect URI’s port, before the browser opens. - It opens the authorization URL with
xdg-open, in the browser GNOME or KDE has as default. - It waits for the browser’s request to the redirect path, answers with a short page (“Signed in. You can close this window…”), and stops listening.
On Linux:
- The tab stays open. The browser tab is not closed for you.
- Other paths get a 404. Requests to any other path on that port, such as a favicon, are answered with
404and ignored. - It times out. The listener gives up after 5 minutes (
timeout). - Cancelling the task stops the listener. There is no cancel button: close the tab and the sign-in times out.
Inside an AppImage, the browser is started with the system’s LD_LIBRARY_PATH, not the image’s.
The provider must allow the loopback redirect URI. iya-sts accepts loopback URIs on any port (RFC 8252 §7.3). Register http://127.0.0.1:53682/callback and http://127.0.0.1:53682/logged-out for the demo’s client; the registration script does it with --config Demo/Sources/CAEPDemo/Resources/OIDCConfiguration-Linux.plist. Use 127.0.0.1, not localhost: the listener binds IPv4, and a browser may try ::1 for localhost first.
A loopback redirect is weaker than a private-use scheme in one way: while the sign-in is in progress, another program running as the same user could listen on the port first. PKCE keeps a code it captures useless to it, and state keeps a forged response out.
Where tokens and keys are kept
The library’s rule is the same on both platforms: cache tokens in the platform’s secure storage when there is one, otherwise in memory.
- macOS has the Keychain.
defaultTokenStore()returns aKeychainTokenStore. The DPoP key goes to the Secure Enclave when the Mac has one (preferredDPoPKeyStore()), so a stolen refresh token can’t be used on any other machine. - Linux has no store this library uses. The GNOME Keyring and KWallet Secret Service, and TPM-backed keys, are not supported yet. So
defaultTokenStore()returns aMemoryTokenStore, andmakeClient()keeps the DPoP key in aMemoryKeyStore. Nothing is written to disk. Quitting the app ends every account’s session in the app; the provider’s session in the browser remains, so signing in again may need no password.
To keep tokens on Linux anyway, pass a TokenStore of your own to AccountManagerOptions(store:). Pair it with DPoP. Without DPoP, AccountManager logs a warning for any persistent store.
TLS trust
Both platforms verify the provider’s and the transmitter’s certificates by default. The demo’s default provider, a local iya-sts, uses certificates from its own private CA, which neither platform trusts. Three settings in the configuration file handle that.
The Linux demo’s built-in configuration turns the checks off (InsecureSkipTLSVerification true in OIDCConfiguration-Linux.plist), so that it works against a local iya-sts with nothing to set up. Its log says so when it starts, and Protections in effect shows TLS: VERIFICATION OFF. To keep the checks on, set it to false and list iya-sts’s root under TrustedCertificates, as below. The macOS demo’s configuration leaves the checks on.
| Key | Type | Default | |
|---|---|---|---|
TrustedCertificates |
array of strings | — | PEM or DER files, or inline PEM text. Each may hold a trust anchor (a root) or a whole chain (leaf, intermediates, root); every certificate counts as an anchor. Relative paths are resolved against the configuration file’s folder; ~ is allowed. |
TrustSystemRoots |
bool | true |
Whether the system’s trusted roots still count beside TrustedCertificates. With false, only the listed certificates are trusted. |
InsecureSkipTLSVerification |
bool | false |
Accept any certificate. For a local test provider only: anybody who can intercept the connection can then impersonate the provider, its signing keys and its CAEP signals. The library logs a warning when it is on. |
The host name is always checked, except with InsecureSkipTLSVerification.
- macOS: the certificates are added as anchors to the URLSession server-trust evaluation (
SecTrustSetAnchorCertificates).TrustSystemRootsfalse setsSecTrustSetAnchorCertificatesOnly. - Linux: URLSession there can neither take extra CAs nor skip verification. With either setting, requests are made with the system’s
curl, given a private CA bundle (--cacert) or--insecure.- The bundle holds the system roots, when allowed, and your certificates.
- It is written to the temporary folder, readable by your user only.
- Request headers, which carry tokens, are passed through a private file, never on the command line, so other users can’t read them in the process list.
In code, the same settings are TLSTrust and URLSessionTransport(trust:) or URLSessionTransport(insecureSkipTLSVerification:). OIDCAppConfiguration.makeTransport() returns the transport the file asks for. Pass that one transport to the client and to every SSFReceiverConfiguration.
To trust a local iya-sts, save the root CA it sends with its chain:
echo | openssl s_client -connect localhost:8081 -showcerts 2>/dev/null \
| awk '/-----BEGIN CERTIFICATE-----/{n++} n==4' | sed '/-----END CERTIFICATE-----/q' \
> ~/.config/caep-demo/sts-root.pem
openssl x509 -in ~/.config/caep-demo/sts-root.pem -noout -subject # subject=CN = sts Root CA, O = sts
Then list it under TrustedCertificates. The browser has its own trust store, so it must trust the same certificate for the sign-in page.
The demo’s user interface
The demo has one model (Demo/Sources/CAEPDemo/DemoModel.swift) shared by both front ends:
- the accounts;
- the CAEP stream of the active account;
- the event policies;
- the event log.
The front ends show the same layout:
- a top bar with the account menu;
- banners;
- the Identity tab: sign-in, protections in effect, session, token cache, tokens;
- the CAEP events tab: stream, event-type picker, verification, reconnect, event log.
Differences in the Linux (GTK) front end:
| macOS (SwiftUI) | Linux (GTK via SwiftCrossUI) | |
|---|---|---|
| Tabs | A tab view | Two toggle buttons above the content |
| Cards | Group boxes | Headed sections separated by rules |
| Token and payload details | Collapsible sections | Shown in full, selectable |
| Event-type picker | A grid of checkboxes | A column of checkboxes |
| Redraw | Swift Observation, as the model changes | Once a second and after every action (SwiftCrossUI does not follow Swift Observation) |
| Rendering | Core Animation | GTK’s Cairo renderer in the AppImage (GSK_RENDERER=cairo); set GSK_RENDERER=gl to use the GPU |
--version |
— | Prints the version and exits without a window |
Running the Linux demo
From the AppImage
install/appimage-docker.sh # no Swift needed: builds in the Swift 6.1 Ubuntu 22.04 image
./dist/CAEP_Demo-0.1.0-x86_64.AppImage
install/appimage.sh builds the image directly where Swift 6.1 and libgtk-4-dev are installed; the AppImage workflow runs it on every push and uploads the result as the caep-demo-x86_64 artifact.
- What it contains: the demo and every library it needs besides the system C library and the host OpenGL loader. The Swift runtime is linked in statically.
- Where it runs: it uses the glibc of the machine that built it, so the CI copy runs on Ubuntu 22.04 and newer.
- Without FUSE: run it with
APPIMAGE_EXTRACT_AND_RUN=1.
From source
sudo apt install libgtk-4-dev # and Swift 6.1 from swift.org
cd Demo && swift run CAEPDemo
Configuration
The configuration is the first of:
OIDC_CONFIG=/path/to/file.plist;~/.config/caep-demo/OIDCConfiguration.plist;- the built-in
OIDCConfiguration-Linux.plist.
To point the demo at another provider, or add TrustedCertificates, copy the built-in file to the second location and edit it.