Skip to content

Join your company with an enrolment token - #832

Merged
kipavy merged 16 commits into
devfrom
feat/757-enroll-consumers
Nov 9, 2026
Merged

kipavy merged 16 commits into
devfrom
feat/757-enroll-consumers

Conversation

@kipavy

@kipavy kipavy commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Lets people join their company from an enrolment token, and lets IT put that token on a machine. Closes the "voltius-cli enroll <token>" and "Client: enrolment first-launch flow" items on #757.

IT side. voltius-cli enroll <token> checks the token with its server and writes it into the machine policy file as enrollment.token (a Rust copy of the token parser, tested against the shared fixture). Running it again with the same token changes nothing and exits 0, even offline; a revoked token exits 3 so a fleet run notices. --json reports changed for Ansible, --no-verify skips the check for image builds, --show never prints the secret, --remove takes it off. It refuses when the machine's policy pins another server and forbids others, the same rule the app uses.

Employee side. The token can arrive three ways: written by voltius-cli enroll, an enroll link (voltius://enroll?t=… or https://voltius.app/open#enroll?t=…), or pasted (first-launch "Have an enrolment token?" field, or Ctrl+K). All three open one "Sign in to " form: create an account or sign in on the token's server, the join request is sent, then the outcome (joined, waiting for an admin, verify your email with Resend, no free seat). At first launch it fills the screen; from a running app it opens as a modal and keeps the other account in the switcher. Local accounts, including the passwordless "Skip for now" one, go through the existing link-to-cloud rules, now shared with CloudAuthModal.

Safety.

  • Nothing is sent to the company until the person presses a button; the app never re-sends a request on its own (a re-send after a denial would open a new request).
  • Tokens from a link or a paste first show which server they point at ("Only continue if your company sent you this link"). Only tokens written on the machine skip that step. An http:// server shows its scheme.
  • A machine policy that pins another server blocks the token before anything is sent, in the form, the palette and the inbox.

Status afterwards lives in notifications: an invite when the machine has a token and the account isn't in the team yet, "waiting for approval", "verify your email", "declined" with Ask again, and a "You joined" message. It updates live from the server and reloads whenever the live connection comes back.

Admins get Copy link next to the token, for people on their own devices.

Needs VoltiusApp/server#129 deployed first (coded not-found, team_id, the joiner's request list and its live event). Against older servers the form says the server doesn't support enrolment tokens yet and the inbox status stays absent.

Screens of this branch against a private server: https://claude.ai/artifact/1Gbg53FmAqW6MthfKLFDc3

Tests: full src/ vitest 8791 passed, tsc clean, cargo test policy:: cli:: 230 passed, clippy clean. tests/pluginBundleBuild and tests/pluginCatalogPublish fail only from a worktree with symlinked node_modules (known). Not live-tested on a real Android or iOS device; mobile screens are the mobile layout in the desktop build.

Related: web bridge VoltiusApp/web (enroll route in /open), docs stacked on VoltiusApp/docs#71.

kipavy added 16 commits November 9, 2026 15:42
Matches the app's serverAllowed: a server.url lock without
server.allowOther=false no longer blocks a token for another server.
One block_on_timeout helper now runs both the enrol resolve and the
plugin catalogue fetch.
- Closing the enrol modal is ignored while a submit or Join runs; each
  open is its own mount, so a late result never lands in a later open.
- The machine server lock gates every resolve in the store: the palette
  shows the managed refusal, the inbox offers no invite.
- An active-session redeem reloads my join requests.
- A saved account on the token's server preselects Sign in.
- Paste fields accept the enrol link as well as the bare token.
- A cleartext token server shows http:// in its host label.
- Retry-After is capped at one day.
- Shared activeAccountAuth, tokenHost and CopyButton; clipboard
  rejection is caught.
- invoke from @/lib/invoke; voltius-enrollment is device-scoped.
- fr: jeton d'enrôlement; changelog and comment fixes.
@kipavy
kipavy merged commit 807ed56 into dev Nov 9, 2026
8 checks passed
@kipavy
kipavy deleted the feat/757-enroll-consumers branch November 9, 2026 22:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant