go-nc-exapp
Shared Go library for Nextcloud ExApp Services: AppAPI authentication, OCS JSON calls, per-user ExApp preferences, and an optional Required Groups Access Gate.
Import: gitea.neitzel.de/konrad/go-nc-exapp (package gonexapp).
Scope
Included
- Credentials — Nextcloud base URL, AppAPI secret, and requesting user identity
- AuthHeaders — outbound AppAPI authorization for OCS and other Nextcloud calls
- WithUser — credentials scoped to a specific requesting user
- UserFromRequest — extract the requesting user from inbound AppAPI-proxied requests
- OCSClient — authenticated OCS calls that always append
format=json - AppAPIPreferences — parameterized get/set of a string ExApp preference (caller supplies app id and key)
- Access Gate — optional Required Groups enforcement (
Wrap+Check), English denied HTML for browsers (200 +frame-ancestors 'self'), positive membership cache; default skip for lifecycle paths and/js/top-menu scripts; env helpers forREQUIRED_GROUPS/REQUIRED_GROUPS_CACHE_SECONDS - Top Menu visibility —
TopMenuAdminRequiredhelper for deploy envTOP_MENU_ADMIN_REQUIRED(0/1for AppAPI top-menu OCS)
Excluded
- ExApp lifecycle HTTP routes (
/heartbeat,/enabled, …) — the Gate skips these by default but does not implement them - HaRP listen /
serve()and unix-socket bootstrap - Top-menu, script, and iframe UI registration
- WebDAV and file storage (see go-nc-files)
- Visit folder resolution (see go-nc-files)
Usage
cred := gonexapp.Credentials{
BaseURL: "https://nextcloud.example",
AppID: "myexapp",
AppVersion: "0.1.0",
AAVersion: "1.0.0",
AppSecret: os.Getenv("APP_SECRET"),
UserID: "alice",
}
prefs := gonexapp.NewAppAPIPreferences(cred, "myexapp", "savedDefault")
value, err := prefs.Get()
groupsEnv, groupsSet := os.LookupEnv("REQUIRED_GROUPS")
groups := gonexapp.ResolveRequiredGroups(groupsEnv, groupsSet, nil)
ttl := gonexapp.ParseCacheSeconds(os.Getenv("REQUIRED_GROUPS_CACHE_SECONDS"), gonexapp.DefaultCacheSeconds)
handler := gonexapp.AccessGate{Cred: cred, Groups: groups, CacheTTL: ttl}.Wrap(inner)
Each ExApp chooses its own preference keys; this library does not hardcode product-specific names.
Declare REQUIRED_GROUPS and REQUIRED_GROUPS_CACHE_SECONDS in the ExApp info.xml so Deploy options can set them.
The Gate skips /heartbeat, /enabled, /init, and any path under /js/ (AppAPI top-menu bootstrap). Serve the registered top-menu script under /js/… so a non-member still loads it and can show Denied UI in the Nextcloud shell. API routes stay gated.
Denied HTML is 200 with Content-Security-Policy: … frame-ancestors 'self'. Without that header AppAPI’s proxy defaults to frame-ancestors 'none' and a denied iframe stays blank. Non-HTML denials remain 403.
Top Menu visibility (TOP_MENU_ADMIN_REQUIRED)
Declare in info.xml under <environment-variables>. At enable time the ExApp reads the env and passes "0" or "1" to AppAPI’s top-menu OCS adminRequired. Only 0 and 1 are valid; anything else falls back to DefaultTopMenuAdminRequired (true → admins only).
adminRequired := gonexapp.TopMenuAdminRequired(
os.Getenv(gonexapp.EnvTopMenuAdminRequired),
gonexapp.DefaultTopMenuAdminRequired,
)
// use adminRequired in POST …/ui/top-menu when registering the menu entry
Applying a change: AppAPI registers the top menu when the ExApp receives PUT /enabled?enabled=1. Changing the deploy env alone does not update the menu entry.
- Set the new value in Deploy options (UI) or
occ app_api:app:register … --env TOP_MENU_ADMIN_REQUIRED=…/ update deploy config. - Recreate or restart the ExApp container so the new env is present.
- Re-run lifecycle: disable then enable the ExApp (UI or
occ app_api:app:disable/app_api:app:enable), orocc app_api:app:update … -eafter an image/info update.
Route access_level in info.xml is separate and only changes when AppAPI re-reads info.xml on register/update — not via this env.
Runnable package examples: go test -run Example.
Domain language
See CONTEXT.md for AppAPI credentials, Requesting user, ExApp preference, OCS, Required Groups, Access Gate, and Top Menu visibility terminology.
Testing
Unit tests use httptest fake OCS servers. No live Nextcloud is required for Library CI.
Related
- go-nc-files — WebDAV, Working Folder, Saved Default, Visit resolution
- Workspace ADR 0013 — extraction from CheckDNS
- Workspace ADR
docs/adr/go-nc-exapp/0001-required-groups-access-gate.md— Access Gate decisions