Summary
Replace the pasted personal API token with a real sign-in flow to share.geolibre.app: OAuth 2.0 with PKCE, short-lived access tokens plus refresh, and scoped tokens the user can list and revoke.
Why
Today "signed in" means the user generated a personal API token on the website and pasted it into Settings. From apps/geolibre-desktop/src/hooks/useDesktopSettings.ts and share-gallery.ts, that token:
- is long-lived with no expiry, so it is valid until manually rotated;
- is all-or-nothing — the same string that lists your private projects can also publish and overwrite them;
- lives in
localStorage, so on the web build it shares the exposure surface of any other localStorage entry (the code comment says as much);
- has no in-app revocation or "where is this token being used" surface;
- makes the sign-in step a copy-paste chore, which is the reason most people never turn on the gallery's "my projects" view at all.
Every other item in the access-control umbrella (organizations, groups, per-item roles, audit trails) needs an identity it can attribute an action to. A shared secret in localStorage is not that.
Proposal
1. OAuth 2.0 + PKCE
- Web build: authorization-code flow with PKCE in a popup, redirecting back to the app origin.
- Desktop: the same flow via a loopback redirect (
http://127.0.0.1:<ephemeral>/callback) or a registered deep link, opening the system browser rather than an in-app webview so the user sees the real address bar.
- Short-lived access token with a refresh token; silent renewal, and a clear "signed out — sign in again" state rather than a mystery 401.
2. Scopes
Issue tokens scoped to what the caller needs, so a leaked token is not a full account takeover:
| Scope |
Grants |
read:projects |
List and open the user's own projects, including unlisted and private |
write:projects |
Create, update, delete the user's projects |
share:public |
Raise a project's visibility to public |
admin:org |
Organization administration (see the organizations issue) |
The gallery's read path (fetchMyProjects) needs only read:projects; publishing needs write:projects. Keep personal API tokens as a supported path for scripting and CI, but make them scoped and expiring too.
3. Session management UI
A Settings section listing active sessions and tokens — created date, last used, scopes, device label — with a per-entry Revoke and a "revoke everything else". The client keeps its own copy in sync by treating a 401 as "revoked, re-authenticate".
Scope notes
- Backwards compatibility: existing pasted tokens must keep working through at least one release, with an in-app prompt to migrate.
shareAuthorizedFetch already restricts the token to the share host and never sends it to third-party hosts a project references; keep that invariant for the OAuth token and add a test.
- Token storage is a separate issue (OS secure storage) — this one should not leave the new refresh token sitting in
localStorage on desktop.
- The Mac App Store build has no external plugin install and no Earth Engine sign-in; check the sandbox allows the loopback/deep-link redirect before assuming parity.
Effort
Medium in the app; the substantive work is the authorization server on share.geolibre.app.
Part of #1665 (access control umbrella).
Summary
Replace the pasted personal API token with a real sign-in flow to
share.geolibre.app: OAuth 2.0 with PKCE, short-lived access tokens plus refresh, and scoped tokens the user can list and revoke.Why
Today "signed in" means the user generated a personal API token on the website and pasted it into Settings. From
apps/geolibre-desktop/src/hooks/useDesktopSettings.tsandshare-gallery.ts, that token:localStorage, so on the web build it shares the exposure surface of any otherlocalStorageentry (the code comment says as much);Every other item in the access-control umbrella (organizations, groups, per-item roles, audit trails) needs an identity it can attribute an action to. A shared secret in
localStorageis not that.Proposal
1. OAuth 2.0 + PKCE
http://127.0.0.1:<ephemeral>/callback) or a registered deep link, opening the system browser rather than an in-app webview so the user sees the real address bar.2. Scopes
Issue tokens scoped to what the caller needs, so a leaked token is not a full account takeover:
read:projectsunlistedandprivatewrite:projectsshare:publicpublicadmin:orgThe gallery's read path (
fetchMyProjects) needs onlyread:projects; publishing needswrite:projects. Keep personal API tokens as a supported path for scripting and CI, but make them scoped and expiring too.3. Session management UI
A Settings section listing active sessions and tokens — created date, last used, scopes, device label — with a per-entry Revoke and a "revoke everything else". The client keeps its own copy in sync by treating a 401 as "revoked, re-authenticate".
Scope notes
shareAuthorizedFetchalready restricts the token to the share host and never sends it to third-party hosts a project references; keep that invariant for the OAuth token and add a test.localStorageon desktop.Effort
Medium in the app; the substantive work is the authorization server on
share.geolibre.app.Part of #1665 (access control umbrella).