User Management & RBAC
GeoLens uses role-based access control with three roles: viewer, editor, and admin. The role set is fixed; what each role can do is configurable. Most day-to-day administration happens through the admin web UI at /admin; the same actions are available via the REST API for scripting and automation.
Replace https://geolens.example.com with your GeoLens instance’s URL in every example below.
Roles & permissions
Section titled “Roles & permissions”The default role hierarchy is viewer -> editor -> admin. The default permission matrix is defined in code at backend/app/core/permissions.py (validated by validate_permission_matrix in backend/app/modules/auth/permissions.py) and can be customized by an admin via Admin -> Settings -> Permissions.
| Capability | viewer | editor | admin |
|---|---|---|---|
upload (upload data files) | No | Yes | Yes |
create_layers (create empty layers) | No | Yes | Yes |
export (export datasets) | Yes | Yes | Yes |
edit_metadata (edit dataset metadata) | No | Yes | Yes |
manage_collections (create/delete collections) | No | Yes | Yes |
use_ai_chat (use AI styling/chat) | No | Yes | Yes |
manage_users (create/edit users) | No | No | Yes |
manage_settings (edit system settings) | No | No | Yes |
Endpoints that require a capability declare it through the require_permission() dependency, which resolves the caller’s roles from the database and evaluates them against the effective matrix on each request. A user receives a 403 Forbidden if their role lacks the capability for the requested endpoint, regardless of dataset visibility.
Self-registration approval
Section titled “Self-registration approval”GeoLens ships with self-registration disabled by default. With REGISTRATION_ENABLED=true in .env, the login screen exposes a Sign up link; new accounts created through it land in a pending state and require an admin to approve them before they can log in.
To enable:
REGISTRATION_ENABLED=trueREGISTRATION_ENABLED is a runtime setting: the environment variable supplies the initial value, and an admin can toggle it afterwards under Admin -> Settings -> Auth without restarting the stack (unless the instance runs with ENV_ONLY_CONFIG=true, which pins every setting to its env value).
Pending users appear in Admin -> Users under the Pending status filter. Use the row’s actions menu: Approve (pick the role to assign — a self-registered account has no role until then) or Reject, which deletes the registration. A pending account’s role and status cannot be edited directly; a PATCH /api/admin/users/{user_id} that carries role, status, or the legacy is_active for a pending user is refused with 422 (an email-only PATCH still succeeds). Use POST /api/admin/users/{user_id}/approve/ (body {"role": "viewer"}) or POST /api/admin/users/{user_id}/reject/ instead. Until approved, login attempts return 403 Forbidden because the account is pending approval.
For SSO-managed organizations, leave REGISTRATION_ENABLED=false and provision users through OAuth/OIDC. See OAuth/OIDC setup for the provider configuration walkthrough.
Managing users via the admin UI
Section titled “Managing users via the admin UI”Navigate to Admin -> Users to see every account on the instance. The list shows username, email, roles, status (active, pending, suspended, deactivated), file storage used, last login, and creation date. The header + Add User button opens the create dialog.
The create dialog requires a username (3 characters or more), an email address, a password, and a role. Email is mandatory in the UI; the REST API accepts a user without one. The username is the unique identifier used for login and audit logs; the password must meet the configured policy (by default at least 12 characters drawn from 3 of the 4 classes — lowercase, uppercase, digit, symbol; see Configuration Reference). Role is required and defaults to viewer.
Use the Deactivate row action to block login without deleting the user’s data. Deactivated users keep their datasets, maps, and collections. The suspended status also blocks login. Reactivate either status by setting it to active.
Use the Reset password menu action to set a new password for a user who has locked themselves out, or who has lost access to their own account recovery. The dialog asks for the new password only — no current password — since holding manage_users is the authorization and the action is written to the audit log. Resetting revokes the account’s existing sessions, refresh tokens, and API keys, so a leaked old password stops working immediately; tell the user the new password out of band. You can reset your own local password; doing so signs you out too.
Reset is supported for local-password accounts, including local accounts that have linked an OAuth/OIDC identity. It is refused for accounts managed only by an identity provider: reset those credentials with the provider. A GeoLens reset does not change the provider’s password or override the instance’s password-login policy.
Unreleased UI changes: the next release disables Reset password for provider-only accounts and adds an All roles filter to the user list. Role filtering can be combined with status and search.
Deleting a user is permanent. Their API keys, saved searches, OAuth links, and role assignments are deleted with them; their datasets, maps, collections, and jobs survive but lose their owner (the owner field is set to null), and their audit-log entries are retained with a null actor. An ownerless dataset is also exempt from per-user quota accounting — its bytes and its row count against nobody — so after a deletion the instance total no longer equals the sum of the per-user meters. You cannot delete your own account, and you cannot delete the last remaining active admin — both are refused with 400.
Managing users via the API
Section titled “Managing users via the API”All user-administration endpoints require the manage_users capability (admin role). Obtain a JWT token first:
# Both admin credentials are written to .env at install time. The username# defaults to `admin` but the installer lets you change it, so read both:# export GEOLENS_ADMIN_USERNAME="$(grep '^GEOLENS_ADMIN_USERNAME=' .env | cut -d= -f2-)"# export GEOLENS_ADMIN_PASSWORD="$(grep '^GEOLENS_ADMIN_PASSWORD=' .env | cut -d= -f2-)"TOKEN=$(curl -s -X POST https://geolens.example.com/api/auth/login \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "username=$GEOLENS_ADMIN_USERNAME" \ --data-urlencode "password=$GEOLENS_ADMIN_PASSWORD" | jq -r '.access_token')Create a user
Section titled “Create a user”curl -X POST https://geolens.example.com/api/admin/users \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "username": "analyst1", "password": "Analyst-Temp-2026!", "role": "editor" }'Passwords must meet the configured policy — by default at least 12 characters drawn from 3 of the 4 classes (lowercase, uppercase, digit, symbol). A password that fails the policy is refused with 422.
List all users
Section titled “List all users”curl https://geolens.example.com/api/admin/users \ -H "Authorization: Bearer $TOKEN"Supports pagination: ?skip=0&limit=50.
Unreleased: the development branch also accepts role=admin,
role=editor, or role=viewer. The filter matches an assigned role, including
users with more than one role; omit it to include all roles.
User responses in that release also expose can_reset_password so clients can
gate the reset action without inferring eligibility from linked providers.
Get a specific user
Section titled “Get a specific user”curl https://geolens.example.com/api/admin/users/{user_id} \ -H "Authorization: Bearer $TOKEN"Update a user
Section titled “Update a user”curl -X PATCH https://geolens.example.com/api/admin/users/{user_id} \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"role": "admin"}'A role change takes effect immediately, including for tokens already issued: role is never read from the JWT — every capability check resolves the caller’s roles from the database on the request that needs them. Changing a role does invalidate that user’s existing API keys; see API keys below.
Approve or reject a pending user
Section titled “Approve or reject a pending user”curl -X POST https://geolens.example.com/api/admin/users/{user_id}/approve/ \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"role": "viewer"}'Rejecting deletes the registration:
curl -X POST https://geolens.example.com/api/admin/users/{user_id}/reject/ \ -H "Authorization: Bearer $TOKEN"Deactivate a user
Section titled “Deactivate a user”Deactivating a user prevents them from logging in without deleting their data:
curl -X POST https://geolens.example.com/api/admin/users/{user_id}/deactivate \ -H "Authorization: Bearer $TOKEN"Reset a user’s password
Section titled “Reset a user’s password”curl -X POST https://geolens.example.com/api/admin/users/{user_id}/reset-password/ \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"password": "Temp-Reset-2026!"}'The new password must meet the configured policy. The response is 422 for a provider-only account, and 404 if no such user exists. Local accounts with linked OAuth/OIDC identities remain eligible. Resetting revokes the account’s existing sessions, refresh tokens, and API keys — including the caller’s own, if resetting their own account.
API keys
Section titled “API keys”API keys are long-lived credentials suitable for scripts, scheduled jobs, and machine clients. Each key is scoped to a single user account. A full key (the default) inherits that user’s permissions; a read_only key authenticates safe methods (GET, HEAD, OPTIONS) and refuses other methods with 403, with a small documented carve-out for endpoints that are reads in spirit — the SQL sandbox POST /api/query/ and STAC item search. The carve-out runs both ways: GET /api/datasets/{dataset_id}/validate/?refresh=true recomputes and persists a quality score, so it is the one safe-method request a read_only key is refused (the same route without refresh=true is served normally). There is no separate “service account” role. Keys can only be minted for active users; any other owner status is refused with 409.
Issuing a key (admin UI)
Section titled “Issuing a key (admin UI)”- Navigate to Admin -> Users, open the target user’s actions menu, and choose Edit.
- Scroll to the API Keys section of the dialog.
- Click Create Key, enter a key name (e.g., “ETL pipeline 2026-01”), pick a scope (Full access or Read only), and copy the key value when it is revealed.
The key value is shown once. There is no way to retrieve it again. Keys are stored as SHA-256 hashes; the raw key is never persisted and cannot be recovered. If lost, revoke the key and issue a new one.
Issuing a key (API)
Section titled “Issuing a key (API)”curl -X POST https://geolens.example.com/api/admin/api-keys/ \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "user_id": "{user_id}", "name": "ETL pipeline 2026-01", "scope": "full" }'scope is full (the default) or read_only. An optional expires_at — an RFC 3339 timestamp that must be in the future — mints an expiring key; omit it for a non-expiring one. Expired keys stop authenticating.
The response includes the full key value. Capture it immediately. Subsequent reads (GET /api/admin/api-keys/) return only the key name and metadata, never the key value.
Revoking a key
Section titled “Revoking a key”curl -X DELETE https://geolens.example.com/api/admin/api-keys/{key_id} \ -H "Authorization: Bearer $TOKEN"Revocation takes effect on the next request. There is no “rotate” operation: issue a new key, update consumers, then revoke the old one.
For the request-side details (header form vs query-string form, resolution order against JWT and OAuth), see API authentication.
Other admin tools
Section titled “Other admin tools”The admin web UI (/admin) exposes several operator tools beyond user management. The most useful are:
-
Audit Log (
/admin/audit): Browse and filter the full audit log with action, user, resource, and date filters. Use this page to investigate “who changed what” without writing API queries. -
Jobs (
/admin/jobs): Lists all ingestion jobs across all users with status, source filename, and timing. Failed jobs link to the error message and the user who started them. Useful for triaging stuck or repeatedly failing imports. -
Published Maps (
/admin/shared-maps): system-wide view of every share link on the instance — map name, link status, embed-token count, expiry, creation date, and creator. Expand a row to see that map’s embed tokens with their use count, last-used time, expiry, and allowed origins; share links and embed tokens (individually or in bulk) can be revoked from here without finding the parent map first. Use this to audit external sharing, especially before public events or when rotating leaked tokens. -
Config Ops (
/admin/config-ops): Export the entire instance configuration (settings + OAuth providers, secrets redacted) as a JSON file, or import a previously exported configuration in eithermergeoroverwritemode. The dry-run button shows exactly what would change before applying anything. Use this to copy configuration between dev/staging/prod instances or to back up settings before major upgrades.
The companion Validate Connectivity button on Config Ops probes storage, cache, and every enabled OIDC provider and reports per-provider latency and error details. Useful for diagnosing post-deployment issues without SSH access. See Infrastructure & Monitoring for the connectivity-probe details.
See also
Section titled “See also”- OAuth/OIDC setup: provisioning users through Google, GitHub, Microsoft Entra ID, and generic OIDC providers
- Settings reference: for permission matrix overrides on the Permissions tab
- API authentication: JWT and API key formats with resolution order