Store the tokens and DPoP key in the platform keystore - #53
Merged
Merged
Conversation
gjwgit
requested review from
anushkavidanage,
cdawei,
jesscmoore and
tonypioneer
September 11, 2026 05:55
Contributor
Author
|
Tested extensively with todopod, notepod, diarypod, innerpod, ++ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Moves everything solid_auth persists between runs into the platform
keystore. It was going to plaintext
shared_preferences.Problem
OidcDefaultStorefalls back topackage:shared_preferencesfor itssecureTokensnamespace when nosecureStorageInstanceis passed, andsolid_auth constructed it bare in three places. That namespace holds the
whole credential set:
code_verifier, writtenby
package:oidcsolid_auth_rsa_private— the PEM-encoded DPoP RSA private key,written by
SolidAuthSessionStoreThe DPoP key is the serious one. It binds an access token to this client
through the
cnf.jktthumbprint, so a plaintext refresh token togetherwith a plaintext DPoP private key is not merely credential exposure — it
is everything needed to impersonate the client. On desktop that is
readable by any process running as the user, and ordinary
home-directory backups collect the file (RFC 9700 §4.14).
oidc_default_storewarned about this on every manager construction.Fix
All three constructions now go through one
createSolidTokenStore()in anew
lib/src/auth/solid_token_store.dart, usingoidc_default_store'sown hardened per-platform options rather than hand-rolled ones.
One factory rather than three call sites matters here beyond tidiness:
the warning is emitted per store construction, so fixing only some sites
silences the symptom while leaving the exposure.
grep -rn "OidcDefaultStore()" lib/now returns nothing, so there is no route backto the unencrypted fallback.
flutter_secure_storagemoves from transitive to declared, at the^10.3.1solidpod already uses, so no new version enters the tree. Twostale doc comments are corrected: the factory's "Platform-appropriate
storage", and the session store's claim that the tokens were already
"stored in the same underlying secure storage".
Testing
Verified with todopod on Linux desktop via a path override:
no FlutterSecureStoragewarning went from 4+ per run to 0PlatformException, so the libsecret/GNOME keyring path worksconfirmed rather than just the write
Not yet tested on Android, iOS, macOS, Windows or web. macOS will need
the Keychain Sharing entitlement for
flutter_secure_storageto work atall.
Migration — needs a release note
This changes where solid_auth reads, so a session saved by an older
build is invisible to this one: it reports
No stored session foundand the user logs in once after upgrading. I hit this during testing, so
it is confirmed behaviour, not a theoretical risk. The old plaintext keys
also remain on disk afterwards until something removes them — cleaning
them up would be worth a follow-up, since otherwise the exposed tokens
simply sit there until they expire.
Closes #52