Skip to content

Proposal: Move KernelCI API user onboarding to invite-only “single link” activation (deprecate legacy verification-token flow) #639

@nuclearcat

Description

@nuclearcat

Today user onboarding is split across multiple steps (create user, request verification token, verify, then login), and verification/reset emails contain raw tokens requiring copy/paste into CLI/API calls. This is functional not great UX and adds support friction. I recently implemented an invite-only flow in kernelci-api where a single invite link allows a user to set their password and become verified in one step.

Proposal
Adopt invite-only onboarding as the recommended/primary workflow:

  1. Admin invites a user
  • API: POST /user/invite (admin-only) creates the user (if missing) and generates an invite token + link.
  • Web UI: GET /user/invite provides a minimal invite form and shows the computed “public” URL base before sending.
  1. User accepts invite (one step)
  • API: POST /user/accept-invite with {token, password} sets password + marks user verified.
  • Web UI: GET /user/accept-invite?token=... provides a minimal password-set page.
  1. Login continues to require verified users
  • Existing /user/login behavior remains: requires verification (now satisfied via invite acceptance).

Motivation / Why change

  • UX: one link to activate + set password is the common expectation for invite-only systems.
  • Operational simplicity: removes the “request verification token” step and token copy/paste.
  • Consistency: aligns with staging workflow (accounts created by admins/sysadmins).
  • Security: keeps admin-only creation; invite token is signed JWT with expiry.
  • Works with and without SMTP: admins can request return_token=true and send_email=false to distribute link manually.

URL generation / reverse proxy support
Invite links use the following resolution order:

  1. PUBLIC_BASE_URL env var (recommended)
  2. X-Forwarded-Host header
  3. request.base_url fallback

Admin can preview resolved URL via GET /user/invite/url before sending invites.

Compatibility / Impact

  • Existing user records remain valid.
  • Existing auth tokens continue to work unchanged.
  • Password reset flow remains unchanged (/user/forgot-password, /user/reset-password).
  • Legacy email verification-token endpoints have been removed in favor of invite acceptance.

Testing

  • Added e2e coverage for invite flow without SMTP: tests/e2e_tests/test_user_invite.py uses send_email=false and validates invite -> accept -> login.
  • CI helper script ci-checks.sh mirrors GitHub workflows (pycodestyle + docker-compose + pylint + pytest).

Follow-ups / TODO

  • Add e2e coverage for durable pubsub (subscriber_id) reconnect/catch-up semantics and ownership enforcement (tracked in TODO.md).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions