obacht

obacht is in early development and not ready for families yet. Follow along on GitHub

Permissions per parent

On this page

By default every parent may do everything in obacht: see every child, change their rules, answer their requests and manage their devices. That fits most families. If you want more, for example grandparents who may see how a child is doing and answer their extra-time requests but not change their rules, or a parent who only looks after one of the children, an external policy decision point can decide what each parent may do.

obacht speaks the vendor-neutral OpenID AuthZEN Authorization API 1.0, so the permissions can live in Keycloak (Authorization Services), or in any other decision point that implements it.

How it works

  • The decision point decides, obacht shows its decisions. When it is turned on, it replaces obacht's default ("every parent may do everything") completely: a parent may do exactly what it allows, nothing more and nothing less. Don't keep permissions in two places; there is nothing to set up about them in obacht itself.
  • Signing in stays with obacht. Who is a parent is still decided by obacht's login (or the parent group of your login provider). The decision point only decides what a signed-in parent may do; allowing something to an account that isn't a parent doesn't let it in.
  • When in doubt, no. If the decision point can't be reached within 5 seconds, answers with an error or with something obacht doesn't understand, the answer is no. The parent app then shows "Your account provider doesn't allow you to do this", and children may disappear from the start page until it is back.
  • At once. obacht doesn't remember answers between requests: a permission you change applies to the next thing the parent does.
  • Devices are not asked about. Children's devices keep following their rules no matter what the decision point says, also when it is down.
  • API tokens act as their parent. An integration such as Home Assistant may do exactly what the parent who created its token may do.

The parent app asks for the parent's permissions once per page and shows what they may not change greyed out, marked "Managed by your account provider". Children a parent may not see are left out everywhere: on the start page, in the device list, in extra-time requests, in notifications (also the weekly summary) and in live updates.

Resources and actions

obacht asks about two kinds of resources.

Resource typeResource idActionAllows
childthe child's idviewseeing the child at all: today's overview, history, apps, activity, devices, special days, Steam
childthe child's idchange_ruleschanging their limits, bedtimes, app rules, special days and settings, pausing their devices
childthe child's idanswer_requestsapproving or denying extra time and new apps, giving extra time without a request
childthe child's idmanage_devicespairing, renaming and removing their devices, DNS and network devices, linking Steam
settingsobachtmanageadding and removing children and parents, creating API tokens, website lists, the router's device list
childthe child's idproposeproposing changes to the child's rules (only a child's own login)

Allow view along with the other actions on a child: the parent app can only open a child the parent may see.

A child's id is in the address of their page in the parent app (https://obacht.example.org/#/child/<id>/today) and in the API (GET /api/v1/children).

Every parent can always change their own password, turn notifications on and off, log out and revoke their own API tokens, and see the list of parents and website lists.

The subject obacht asks about is the parent: type user, id = the sub from your login provider for parents who log in through one (with Keycloak, the user's id), else their obacht username. properties.username is the username, properties.role is parent. obacht sends nothing else about the parent, and about children only their ids: no names, no usage.

A child's own login is asked about too, with properties.role child and properties.child_id the child's id. For a child the decision point can only take away: obacht asks only about view and propose on that child and refuses everything else without asking. Parents are never asked about propose.

Turning it on

Set the base address of the decision point. Without client settings of its own, obacht gets an access token with the OAuth client credentials of its login provider client, at that provider's token endpoint. In Keycloak that is all that's needed, besides turning on Authorization for the client.

services.obacht.authzen = {
  url = "https://login.example.org/realms/home";
  # Only if obacht should use another client than its login's:
  # clientId = "obacht-permissions";
  # clientSecretFile = "/run/secrets/obacht-authzen"; # outside the Nix store
  # tokenUrl = "https://login.example.org/realms/home/protocol/openid-connect/token";
  # Or a fixed bearer token instead of client credentials:
  # tokenFile = "/run/secrets/obacht-authzen-token";
};

Helm: the authzen.* values. Elsewhere, the environment variables:

VariableMeaning
OBACHT_AUTHZEN_URLBase address of the decision point; turns this on. obacht reads <url>/.well-known/authzen-configuration, or uses <url>/access/v1/evaluation(s) when there is none.
OBACHT_AUTHZEN_CLIENT_IDOAuth client for the access token (client credentials). Default: OBACHT_OIDC_CLIENT_ID when a login provider is configured.
OBACHT_AUTHZEN_CLIENT_SECRET or OBACHT_AUTHZEN_CLIENT_SECRET_FILEIts secret (default: the login client's secret).
OBACHT_AUTHZEN_TOKEN_URLToken endpoint. Default: the one of OBACHT_OIDC_ISSUER.
OBACHT_AUTHZEN_TOKEN or OBACHT_AUTHZEN_TOKEN_FILEA fixed bearer token instead of client credentials.
OBACHT_AUTHZEN_REGISTER_CHILDRENtrue: obacht keeps one resource per child at the decision point (below).
OBACHT_AUTHZEN_CHILD_NAMEStrue: those resources also carry the child's name (below).

Without a client and without a token, obacht asks without authentication.

Children as resources

Some decision points, Keycloak among them, only decide about resources they know: a child they have never heard of is refused to everyone. With registerChildren (Nix), authzen.registerChildren (Helm) or OBACHT_AUTHZEN_REGISTER_CHILDREN=true, obacht registers every child there itself, through the standard OAuth UMA 2.0 resource registration (found at <url>/.well-known/uma2-configuration), with the same access token: name = the child's id, type child, the actions as scopes. It does so when a child is added (before the parent app shows them), removes the resource when the child is removed, and checks all of them at start and every 15 minutes. Only the child's id is sent, unless you turn on childNames (Nix), authzen.childNames (Helm) or OBACHT_AUTHZEN_CHILD_NAMES=true: then each resource also carries the child's name as its display name, so whoever sets permissions at the decision point sees whom they are for (Keycloak shows it in the resource list), and a renamed child's resource is renamed too. Nothing else about a child is sent. Resources of type child that don't belong to a child any more are removed; other resources are left alone.

Example: Keycloak

Keycloak answers AuthZEN requests from version 26.7 on, as an experimental feature: start it with --features=authzen (Keycloak's guide). The base address is the realm's, e.g. https://login.example.org/realms/home. This assumes parents log in through Keycloak, so the subject is their Keycloak user.

  1. In obacht's client, turn on Client authentication and Authorization (Keycloak turns on service accounts with it).
  2. Under Authorization → Scopes, create the scopes view, change_rules, answer_requests, manage_devices and manage.
  3. Under Resources, create one: name obacht, type settings, scope manage. Turn on registerChildren (above), and obacht creates one resource per child (type child) itself; without it, create them by hand: name = the child's id, type child, scopes view, change_rules, answer_requests, manage_devices and propose.
  4. Under Policies, describe who is who, e.g. a group policy "Parents" for the group obacht-parents and a user policy "Grandma".
  5. Under Permissions, create scope-based permissions that tie them together, e.g. "Parents" may do every scope on every resource, "Grandma" may view and answer_requests on the children's resources. A permission for the resource type child applies to every child, also to ones added later; one for a single child's resource only to them.
  6. Delete the "Default Permission" Keycloak creates (it allows everything), and set obacht's authzen.url.

Keycloak's policy enforcement mode decides about children it has no resource for yet, e.g. one just added without registerChildren: Enforcing hides them from every parent until you add their resource, Permissive lets every parent do everything with them.

Keycloak only answers about its own users. A child's own login with a password in obacht (not through Keycloak) is unknown to it: Keycloak answers with an error, and obacht refuses that child everything, even seeing themselves. With Keycloak deciding, give children their login through Keycloak too.

Check the result in the parent app logged in as someone else, or with GET /api/v1/permissions and their API token.

This page is part of obacht's documentation, licensed under CC BY 4.0. Source on GitHub · CC BY 4.0 · Version: main (2ab2740)